Commit 427cbf544a42561d8d10bf48933d7218bf095c4d

Authored by Peter M. Groen
1 parent c6c62b01

Preparation Subclassing Subscriber

examples/pub/CMakeLists.txt
@@ -5,7 +5,7 @@ include(projectheader) @@ -5,7 +5,7 @@ include(projectheader)
5 project_header(test_mqtt_pub) 5 project_header(test_mqtt_pub)
6 6
7 include_directories( SYSTEM 7 include_directories( SYSTEM
8 - ${CMAKE_CURRENT_SOURCE_DIR}/../../src 8 + ${CMAKE_CURRENT_SOURCE_DIR}/../../include
9 ) 9 )
10 10
11 include(compiler) 11 include(compiler)
@@ -21,7 +21,7 @@ add_executable( ${PROJECT_NAME} @@ -21,7 +21,7 @@ add_executable( ${PROJECT_NAME}
21 21
22 target_link_libraries( 22 target_link_libraries(
23 ${PROJECT_NAME} 23 ${PROJECT_NAME}
24 - mqtt 24 + mqtt-cpp
25 ) 25 )
26 26
27 set_target_properties( ${PROJECT_NAME} PROPERTIES 27 set_target_properties( ${PROJECT_NAME} PROPERTIES
examples/pub/main.cpp
@@ -78,7 +78,7 @@ int main( int argc, char* argv[] ) @@ -78,7 +78,7 @@ int main( int argc, char* argv[] )
78 { 78 {
79 std::cout << "{OK}" << std::endl; 79 std::cout << "{OK}" << std::endl;
80 std::cout << "Connecting to the broker : "; 80 std::cout << "Connecting to the broker : ";
81 - pPublisher->connect( "localhost", 1883, "", "" ); 81 + pPublisher->connect( "office.osdev.nl", 1883, "", "" );
82 82
83 // Assume we are connected now, start publishing. 83 // Assume we are connected now, start publishing.
84 while( 1 ) 84 while( 1 )
@@ -86,7 +86,7 @@ int main( int argc, char* argv[] ) @@ -86,7 +86,7 @@ int main( int argc, char* argv[] )
86 std::string payload = "<Timestamp value=\"" + std::to_string( getEpochUSecs() ) + "\" /><MessageNumber value=\"" + std::to_string( messageNumber ) + "\" />" ; 86 std::string payload = "<Timestamp value=\"" + std::to_string( getEpochUSecs() ) + "\" /><MessageNumber value=\"" + std::to_string( messageNumber ) + "\" />" ;
87 pPublisher->publish( std::string( "test/publisher/TestPublisher" ), payload ); 87 pPublisher->publish( std::string( "test/publisher/TestPublisher" ), payload );
88 88
89 - sleepcp( 1, T_SECONDS ); 89 + sleepcp( 1, T_MICRO );
90 if( messageNumber > 2000000000 ) 90 if( messageNumber > 2000000000 )
91 messageNumber = -1; 91 messageNumber = -1;
92 92
examples/pub/publisher.cpp
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 * ***************************************************************************/ 21 * ***************************************************************************/
22 22
23 // osdev::components::mqtt 23 // osdev::components::mqtt
24 -#include "token.h" 24 +// #include "token.h"
25 25
26 // mqtt_tests 26 // mqtt_tests
27 #include "publisher.h" 27 #include "publisher.h"
examples/sub/CMakeLists.txt
@@ -5,7 +5,7 @@ include(projectheader) @@ -5,7 +5,7 @@ include(projectheader)
5 project_header(test_mqtt_sub) 5 project_header(test_mqtt_sub)
6 6
7 include_directories( SYSTEM 7 include_directories( SYSTEM
8 - ${CMAKE_CURRENT_SOURCE_DIR}/../../src 8 + ${CMAKE_CURRENT_SOURCE_DIR}/../../include
9 ) 9 )
10 10
11 include(compiler) 11 include(compiler)
@@ -21,7 +21,7 @@ add_executable( ${PROJECT_NAME} @@ -21,7 +21,7 @@ add_executable( ${PROJECT_NAME}
21 21
22 target_link_libraries( 22 target_link_libraries(
23 ${PROJECT_NAME} 23 ${PROJECT_NAME}
24 - mqtt 24 + mqtt-cpp
25 ) 25 )
26 26
27 set_target_properties( ${PROJECT_NAME} PROPERTIES 27 set_target_properties( ${PROJECT_NAME} PROPERTIES
examples/sub/main.cpp
@@ -71,12 +71,12 @@ int main( int argc, char* argv[] ) @@ -71,12 +71,12 @@ int main( int argc, char* argv[] )
71 71
72 std::cout << "Creating the subscriber : "; 72 std::cout << "Creating the subscriber : ";
73 // Create the subscriber 73 // Create the subscriber
74 - Subscriber *pSubscriber = new Subscriber(); 74 + Subscriber *pSubscriber = new Subscriber( "Test_Subscriber" );
75 if( pSubscriber != nullptr ) 75 if( pSubscriber != nullptr )
76 { 76 {
77 std::cout << "[OK]" << std::endl; 77 std::cout << "[OK]" << std::endl;
78 std::cout << "Connecting to the test-broker : " << std::endl; 78 std::cout << "Connecting to the test-broker : " << std::endl;
79 - pSubscriber->connect( "localhost", 1883, "", "" ); 79 + pSubscriber->connect( "office.osdev.nl", 1883, "", "" );
80 std::cout << "Subscribing to the test-topic....." << std::endl; 80 std::cout << "Subscribing to the test-topic....." << std::endl;
81 pSubscriber->subscribe( "test/publisher/TestPublisher" ); 81 pSubscriber->subscribe( "test/publisher/TestPublisher" );
82 82
examples/sub/subscriber.cpp
@@ -20,27 +20,13 @@ @@ -20,27 +20,13 @@
20 * DEALINGS IN THE SOFTWARE. * 20 * DEALINGS IN THE SOFTWARE. *
21 * ***************************************************************************/ 21 * ***************************************************************************/
22 #include "subscriber.h" 22 #include "subscriber.h"
23 -#include "mqttmessage.h"  
24 -#include "credentials.h"  
25 23
26 -Subscriber::Subscriber()  
27 - : m_mqtt_client( "TestSubscriber" )  
28 -{  
29 -  
30 -} 24 +#include <iostream>
31 25
32 -void Subscriber::connect( const std::string &hostname, int portnumber, const std::string &username, const std::string &password ) 26 +Subscriber::Subscriber( const std::string &client_id )
  27 + : MqttSubscriberBase( client_id )
33 { 28 {
34 - m_mqtt_client.connect( hostname, portnumber, osdev::components::mqtt::Credentials( username, password ) );  
35 - std::cout << "Client state : " << m_mqtt_client.state() << std::endl;  
36 -}  
37 29
38 -void Subscriber::subscribe( const std::string &message_topic )  
39 -{  
40 - m_mqtt_client.subscribe( message_topic, 1, [this](const osdev::components::mqtt::MqttMessage &message)  
41 - {  
42 - this->receive_data(message.topic(), message.payload() );  
43 - });  
44 } 30 }
45 31
46 void Subscriber::receive_data( const std::string &message_topic, const std::string &message_payload ) 32 void Subscriber::receive_data( const std::string &message_topic, const std::string &message_payload )
examples/sub/subscriber.h
@@ -22,27 +22,19 @@ @@ -22,27 +22,19 @@
22 #pragma once 22 #pragma once
23 23
24 // std 24 // std
25 -#include <memory>  
26 #include <string> 25 #include <string>
27 26
28 -// osdev::components::mqtt  
29 -#include "mqttclient.h"  
30 -#include "compat-c++14.h" 27 +// mqtt-cpp
  28 +#include "mqttsubscriberbase.h"
31 29
32 -class Subscriber 30 +class Subscriber : public MqttSubscriberBase
33 { 31 {
34 public: 32 public:
35 - Subscriber(); 33 + Subscriber( const std::string &client_id );
36 34
37 virtual ~Subscriber() {} 35 virtual ~Subscriber() {}
38 36
39 - void connect( const std::string &hostname, int portnumber, const std::string &username, const std::string &password );  
40 -  
41 - void subscribe( const std::string &message_topic );  
42 -  
43 -private: 37 +protected:
44 void receive_data( const std::string &message_topic, const std::string &message_payload ); 38 void receive_data( const std::string &message_topic, const std::string &message_payload );
45 39
46 -private:  
47 - osdev::components::mqtt::MqttClient m_mqtt_client;  
48 }; 40 };
include/mqttsubscriberbase.h
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#pragma once
  23 +
  24 +// std
  25 +#include <memory>
  26 +#include <string>
  27 +
  28 +#include "mqttclient.h"
  29 +
  30 +
  31 +class MqttSubscriberBase
  32 +{
  33 +public:
  34 + /*!
  35 + * \brief SubscriberBase
  36 + */
  37 + MqttSubscriberBase( const std::string &client_id );
  38 +
  39 + /*!
  40 + * \brief ~SubscriberBase
  41 + */
  42 + virtual ~MqttSubscriberBase() {}
  43 +
  44 + /*!
  45 + * \brief getClientId
  46 + * \return
  47 + */
  48 + std::string getClientId() const;
  49 +
  50 + /*!
  51 + * \brief connect
  52 + * \param hostname
  53 + * \param portnumber
  54 + * \param username
  55 + * \param password
  56 + */
  57 + void connect( const std::string &hostname, int portnumber, const std::string &username, const std::string &password );
  58 +
  59 + /*!
  60 + * \brief subscribe
  61 + * \param message_topic
  62 + */
  63 + void subscribe( const std::string &message_topic );
  64 +
  65 + /*!
  66 + * \brief disconnect
  67 + */
  68 + void disconnect();
  69 +
  70 +protected:
  71 + /*!
  72 + * \brief receive_data
  73 + * \param message_topic
  74 + * \param message_payload
  75 + */
  76 + virtual void receive_data( const std::string &message_topic, const std::string &message_payload ) = 0;
  77 +
  78 +private:
  79 + osdev::components::mqtt::MqttClient m_mqtt_client;
  80 +
  81 +};
src/CMakeLists.txt
@@ -23,15 +23,14 @@ endif() @@ -23,15 +23,14 @@ endif()
23 # ============================================================================== 23 # ==============================================================================
24 include(projectheader) 24 include(projectheader)
25 25
26 -project_header(mqtt) 26 +project_header(mqtt-cpp)
27 27
28 find_package( Boost REQUIRED COMPONENTS regex ) 28 find_package( Boost REQUIRED COMPONENTS regex )
29 29
30 include(compiler) 30 include(compiler)
31 31
32 include_directories( 32 include_directories(
33 - ${CMAKE_CURRENT_SOURCE_DIR}/../logutils  
34 - ${CMAKE_CURRENT_SOURCE_DIR}/../include 33 + ${CMAKE_SOURCE_DIR}/include
35 ) 34 )
36 35
37 set(SRC_LIST 36 set(SRC_LIST
@@ -40,8 +39,6 @@ set(SRC_LIST @@ -40,8 +39,6 @@ set(SRC_LIST
40 ${CMAKE_CURRENT_SOURCE_DIR}/clientpaho.cpp 39 ${CMAKE_CURRENT_SOURCE_DIR}/clientpaho.cpp
41 ${CMAKE_CURRENT_SOURCE_DIR}/commondefs.cpp 40 ${CMAKE_CURRENT_SOURCE_DIR}/commondefs.cpp
42 ${CMAKE_CURRENT_SOURCE_DIR}/connectionstatus.cpp 41 ${CMAKE_CURRENT_SOURCE_DIR}/connectionstatus.cpp
43 - ${CMAKE_CURRENT_SOURCE_DIR}/compiletimedigits.h  
44 - ${CMAKE_CURRENT_SOURCE_DIR}/compiletimestring.h  
45 ${CMAKE_CURRENT_SOURCE_DIR}/credentials.cpp 42 ${CMAKE_CURRENT_SOURCE_DIR}/credentials.cpp
46 ${CMAKE_CURRENT_SOURCE_DIR}/errorcode.cpp 43 ${CMAKE_CURRENT_SOURCE_DIR}/errorcode.cpp
47 ${CMAKE_CURRENT_SOURCE_DIR}/token.cpp 44 ${CMAKE_CURRENT_SOURCE_DIR}/token.cpp
@@ -63,23 +60,23 @@ set(SRC_LIST @@ -63,23 +60,23 @@ set(SRC_LIST
63 ${CMAKE_CURRENT_SOURCE_DIR}/stringutils.cpp 60 ${CMAKE_CURRENT_SOURCE_DIR}/stringutils.cpp
64 ${CMAKE_CURRENT_SOURCE_DIR}/uriparser.cpp 61 ${CMAKE_CURRENT_SOURCE_DIR}/uriparser.cpp
65 # Helper files ( Utillities ) 62 # Helper files ( Utillities )
66 - ${CMAKE_CURRENT_SOURCE_DIR}/bimap.h  
67 - ${CMAKE_CURRENT_SOURCE_DIR}/compat-c++14.h  
68 - ${CMAKE_CURRENT_SOURCE_DIR}/compat-chrono.h  
69 - ${CMAKE_CURRENT_SOURCE_DIR}/histogram.h  
70 - ${CMAKE_CURRENT_SOURCE_DIR}/histogramprovider.h  
71 - ${CMAKE_CURRENT_SOURCE_DIR}/imqttclient.h  
72 - ${CMAKE_CURRENT_SOURCE_DIR}/imqttclientimpl.h  
73 - ${CMAKE_CURRENT_SOURCE_DIR}/lockguard.h  
74 - ${CMAKE_CURRENT_SOURCE_DIR}/macrodefs.h  
75 - ${CMAKE_CURRENT_SOURCE_DIR}/measure.h  
76 - ${CMAKE_CURRENT_SOURCE_DIR}/metaprogrammingdefs.h  
77 - ${CMAKE_CURRENT_SOURCE_DIR}/mqttstream.h  
78 - ${CMAKE_CURRENT_SOURCE_DIR}/stringify.h  
79 - ${CMAKE_CURRENT_SOURCE_DIR}/stringutils.h  
80 - ${CMAKE_CURRENT_SOURCE_DIR}/synchronizedqueue.h  
81 - ${CMAKE_CURRENT_SOURCE_DIR}/utils.h  
82 - ${CMAKE_CURRENT_SOURCE_DIR}/uriutils.h 63 + # ${CMAKE_CURRENT_SOURCE_DIR}/bimap.h
  64 + # ${CMAKE_CURRENT_SOURCE_DIR}/compat-c++14.h
  65 + # ${CMAKE_CURRENT_SOURCE_DIR}/compat-chrono.h
  66 + # ${CMAKE_CURRENT_SOURCE_DIR}/histogram.h
  67 + # ${CMAKE_CURRENT_SOURCE_DIR}/histogramprovider.h
  68 + # ${CMAKE_CURRENT_SOURCE_DIR}/imqttclient.h
  69 + # ${CMAKE_CURRENT_SOURCE_DIR}/imqttclientimpl.h
  70 + # ${CMAKE_CURRENT_SOURCE_DIR}/lockguard.h
  71 + # ${CMAKE_CURRENT_SOURCE_DIR}/macrodefs.h
  72 + # ${CMAKE_CURRENT_SOURCE_DIR}/measure.h
  73 + # ${CMAKE_CURRENT_SOURCE_DIR}/metaprogrammingdefs.h
  74 + # ${CMAKE_CURRENT_SOURCE_DIR}/mqttstream.h
  75 + # ${CMAKE_CURRENT_SOURCE_DIR}/stringify.h
  76 + # ${CMAKE_CURRENT_SOURCE_DIR}/stringutils.h
  77 + # ${CMAKE_CURRENT_SOURCE_DIR}/synchronizedqueue.h
  78 + # ${CMAKE_CURRENT_SOURCE_DIR}/utils.h
  79 + # ${CMAKE_CURRENT_SOURCE_DIR}/uriutils.h
83 ) 80 )
84 81
85 include(library) 82 include(library)
src/bimap.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_BIMAP_H  
23 -#define OSDEV_COMPONENTS_MQTT_BIMAP_H  
24 -  
25 -// boost  
26 -#include <boost/bimap.hpp>  
27 -  
28 -namespace osdev {  
29 -namespace components {  
30 -namespace mqtt {  
31 -  
32 -/**  
33 - * @brief Factory function to create boost::bimap from an initializer list  
34 - *  
35 - * Usage:  
36 - * @code  
37 - * auto myBimap = makeBimap<int, int>( { { 1, 2 }, { 2, 3 } } );  
38 - * @endcode  
39 - */  
40 -template <typename L, typename R>  
41 -boost::bimap<L, R> makeBimap(std::initializer_list<typename boost::bimap<L, R>::value_type> list)  
42 -{  
43 - return boost::bimap<L, R>(list.begin(), list.end());  
44 -}  
45 -  
46 -} // End namespace mqtt  
47 -} // End namespace components  
48 -} // End namespace osdev  
49 -  
50 -#endif // OSDEV_COMPONENTS_MQTT_BIMAP_H  
src/clientpaho.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_CLIENTPAHO_H  
23 -#define OSDEV_COMPONENTS_MQTT_CLIENTPAHO_H  
24 -  
25 -// std  
26 -#include <atomic>  
27 -#include <condition_variable>  
28 -#include <deque>  
29 -#include <functional>  
30 -#include <future>  
31 -#include <map>  
32 -#include <memory>  
33 -#include <mutex>  
34 -#include <string>  
35 -#include <vector>  
36 -  
37 -// boost  
38 -#include <boost/regex.hpp>  
39 -  
40 -// paho  
41 -#include <MQTTAsync.h>  
42 -  
43 -// osdev::components::mqtt  
44 -#include "synchronizedqueue.h"  
45 -#include "imqttclientimpl.h"  
46 -#include "mqttfailure.h"  
47 -#include "mqttsuccess.h"  
48 -  
49 -namespace osdev {  
50 -namespace components {  
51 -namespace mqtt {  
52 -  
53 -/**  
54 - * @brief Wrapper class for the paho-c library.  
55 - * This implementation uses the clean session flag and recreates subscriptions on reconnect.  
56 - *  
57 - * The implementation allows multiple subscriptions as long as the subscriptions do not have overlap. For mqtt 3 it is not  
58 - * possible to track down the subscription based on the incoming message meta information. By matching the topic against  
59 - * the various topic filters a subscription can be identified (but only when there is only one subscription that matches).  
60 - */  
61 -class ClientPaho : public IMqttClientImpl  
62 -{  
63 -public:  
64 - /**  
65 - * @brief Construct a ClientPaho instance.  
66 - * @param endpoint The endpoint to connect to  
67 - * @param id The clientId that is used in the connection.  
68 - * @param connectionStatusCallback The callback on which connection status information is communicated.  
69 - * @param deliveryCompleteCallback Callback that is called with the publish message tokens for messages that are delivered.  
70 - * Being delivered has different meanings depending on the quality of service.  
71 - */  
72 - ClientPaho(const std::string& endpoint,  
73 - const std::string& id,  
74 - const std::function<void(const std::string&, ConnectionStatus)>& connectionStatusCallback,  
75 - const std::function<void(const std::string&, std::int32_t)>& deliveryCompleteCallback);  
76 - virtual ~ClientPaho() override;  
77 -  
78 - // Non copyable, non movable.  
79 - ClientPaho(const ClientPaho&) = delete;  
80 - ClientPaho& operator=(const ClientPaho&) = delete;  
81 - ClientPaho(ClientPaho&&) = delete;  
82 - ClientPaho& operator=(ClientPaho&&) = delete;  
83 -  
84 - /**  
85 - * @see IMqttClientImpl  
86 - */  
87 - virtual std::string clientId() const override;  
88 -  
89 - /**  
90 - * @see IMqttClientImpl  
91 - */  
92 - virtual ConnectionStatus connectionStatus() const override;  
93 -  
94 - /**  
95 - * @see IMqttClientImpl  
96 - */  
97 - virtual std::int32_t connect(bool wait) override;  
98 -  
99 - /**  
100 - * @see IMqttClientImpl  
101 - */  
102 - virtual std::int32_t disconnect(bool wait, int timeoutMs) override;  
103 -  
104 - /**  
105 - * @see IMqttClientImpl  
106 - */  
107 - virtual std::int32_t publish(const MqttMessage& message, int qos) override;  
108 -  
109 - /**  
110 - * @see IMqttClientImpl  
111 - */  
112 - virtual void publishPending() override;  
113 -  
114 - /**  
115 - * @see IMqttClientImpl  
116 - */  
117 - virtual std::int32_t subscribe(const std::string& topic, int qos, const std::function<void(MqttMessage msg)>& cb) override;  
118 -  
119 - /**  
120 - * @see IMqttClientImpl  
121 - */  
122 - virtual void resubscribe() override;  
123 -  
124 - /**  
125 - * @see IMqttClientImpl  
126 - */  
127 - virtual std::int32_t unsubscribe(const std::string& topic, int qos) override;  
128 -  
129 - /**  
130 - * @see IMqttClientImpl  
131 - */  
132 - virtual void unsubscribeAll() override;  
133 -  
134 - /**  
135 - * @see IMqttClientImpl  
136 - */  
137 - virtual std::chrono::milliseconds waitForCompletion(std::chrono::milliseconds waitFor, const std::set<std::int32_t>& tokens) const override;  
138 -  
139 - /**  
140 - * @see IMqttClientImpl  
141 - */  
142 - virtual bool isOverlapping(const std::string& topic) const override;  
143 -  
144 - /**  
145 - * @see IMqttClientImpl  
146 - */  
147 - virtual bool isOverlapping(const std::string& topic, std::string& existingTopic) const override;  
148 -  
149 - /**  
150 - * @see IMqttClientImpl  
151 - */  
152 - virtual std::vector<std::int32_t> pendingOperations() const override;  
153 -  
154 - /**  
155 - * @see IMqttClientImpl  
156 - */  
157 - virtual bool hasPendingSubscriptions() const override;  
158 -  
159 - /**  
160 - * @see IMqttClientImpl  
161 - */  
162 - virtual boost::optional<bool> operationResult(std::int32_t token) const override;  
163 -  
164 -private:  
165 - void parseEndpoint(const std::string& endpoint);  
166 -  
167 - std::int32_t publishInternal(const MqttMessage& message, int qos);  
168 - std::int32_t subscribeInternal(const std::string& topic, int qos);  
169 -  
170 - void setConnectionStatus(ConnectionStatus status);  
171 - bool isOverlappingInternal(const std::string& topic, std::string& existingTopic) const;  
172 -  
173 - /**  
174 - * @brief Internal struct for subscriber information.  
175 - * Used to store subscriptions.  
176 - */  
177 - struct Subscription  
178 - {  
179 - int qos;  
180 - boost::regex topicRegex;  
181 - std::function<void(MqttMessage)> callback;  
182 - };  
183 -  
184 - /**  
185 - * @brief Internal struct for publisher information.  
186 - * Used to store pending publishes during reconnection.  
187 - */  
188 - struct Publish  
189 - {  
190 - int qos;  
191 - MqttMessage data;  
192 - };  
193 -  
194 - /**  
195 - * @brief Add an incoming callback event to the synchronized queue.  
196 - * @param ev A function object that calls one of the event handlers on a ClientPaho instance, but other types of actions are also possible.  
197 - */  
198 - void pushIncomingEvent(std::function<void()> ev);  
199 -  
200 - /**  
201 - * @brief Worker method that executes the events.  
202 - */  
203 - void callbackEventHandler();  
204 -  
205 - /**  
206 - * @brief Callback method that is called when a reconnect succeeds.  
207 - * @param cause The cause of the original disconnect.  
208 - */  
209 - void onConnectOnInstance(const std::string& cause);  
210 -  
211 - /**  
212 - * @brief Callback that is called when a connect call succeeds.  
213 - * This callback is also called when a reconnect succeeds because the paho library reuses the initial connect command!  
214 - * The connection status is set to Connected.  
215 - * @param response A success response with connection data.  
216 - */  
217 - void onConnectSuccessOnInstance(const MqttSuccess& response);  
218 -  
219 - /**  
220 - * @brief Callback that is called when a connect call fails after being sent to the endpoint.  
221 - * This callback is also called when a reconnect fails because the paho library reuses the initial connect command!  
222 - * The connection status is set to Disconnected when the connection state is ConnectInProgress, othwerwise the connection status is left as is.  
223 - * @param response A failure response.  
224 - */  
225 - void onConnectFailureOnInstance(const MqttFailure& response);  
226 -  
227 - //void onDisconnectOnInstance(enum MQTTReasonCodes reasonCode); for MQTT V5 which is not supported by centos7 paho-c  
228 -  
229 - /**  
230 - * @brief Callback that is called when a disconnect call succeeds.  
231 - * The connection status is set to Disconnected.  
232 - * @param response A success response with no specific data.  
233 - */  
234 - void onDisconnectSuccessOnInstance(const MqttSuccess& response);  
235 -  
236 - /**  
237 - * @brief Callback that is called when a disconnect call fails after being sent to the endpoint.  
238 - * Based on the result returned by the paho library The connection status is set to Disconnected or Connected.  
239 - * @param response A failure response.  
240 - */  
241 - void onDisconnectFailureOnInstance(const MqttFailure& response);  
242 -  
243 - /**  
244 - * @brief Callback that is called when a publish call succeeds.  
245 - * This callback is called before the delivery complete callback.  
246 - * @param response A success response with the published message.  
247 - */  
248 - void onPublishSuccessOnInstance(const MqttSuccess& response);  
249 -  
250 - /**  
251 - * @brief Callback that is called when a publish call fails after being sent to the endpoint.  
252 - * @param response A failure response.  
253 - */  
254 - void onPublishFailureOnInstance(const MqttFailure& response);  
255 -  
256 - /**  
257 - * @brief Callback that is called when a subscribe call succeeds.  
258 - * @param response A success response with the subscription information. The actual used qos is conveyed in this response.  
259 - */  
260 - void onSubscribeSuccessOnInstance(const MqttSuccess& response);  
261 -  
262 - /**  
263 - * @brief Callback that is called when a subscribe call fails after being sent to the endpoint.  
264 - * @param response A failure response.  
265 - */  
266 - void onSubscribeFailureOnInstance(const MqttFailure& response);  
267 -  
268 - /**  
269 - * @brief Callback that is called when an unsubscribe call succeeds.  
270 - * @param response A success response with no specific data.  
271 - */  
272 - void onUnsubscribeSuccessOnInstance(const MqttSuccess& response);  
273 -  
274 - /**  
275 - * @brief Callback that is called when an unsubscribe call fails after being sent to the endpoint.  
276 - * @param response A failure response.  
277 - */  
278 - void onUnsubscribeFailureOnInstance(const MqttFailure& response);  
279 -  
280 - /**  
281 - * @brief Callback that is called when a message is received.  
282 - * @param message The message payload and meta data.  
283 - */  
284 - int onMessageArrivedOnInstance(const MqttMessage& message);  
285 -  
286 - /**  
287 - * @brief Callback that is called when the delivery of a publish message is considered complete.  
288 - * The definition of complete depends on the quality of service used in the publish command.  
289 - * @param token The token with the publish command is sent.  
290 - */  
291 - void onDeliveryCompleteOnInstance(MQTTAsync_token token);  
292 -  
293 - /**  
294 - * @brief Callback that is called when the connection is broken.  
295 - * @param cause The reason string. Always "cause unknown" for mqtt3 endpoints.  
296 - */  
297 - void onConnectionLostOnInstance(const std::string& cause);  
298 -  
299 - // Static callback functions that are registered on the paho library. Functions call their *OnInstance() counterparts.  
300 - static void onConnect(void* context, char* cause);  
301 - static void onConnectSuccess(void* context, MQTTAsync_successData* response);  
302 - static void onConnectFailure(void* context, MQTTAsync_failureData* response);  
303 - //static void onDisconnect(void* context, MQTTProperties* properties, enum MQTTReasonCodes reasonCode); for MQTT V5 which is not supported by centos7 paho-c  
304 - static void onDisconnectSuccess(void* context, MQTTAsync_successData* response);  
305 - static void onDisconnectFailure(void* context, MQTTAsync_failureData* response);  
306 - static void onPublishSuccess(void* context, MQTTAsync_successData* response);  
307 - static void onPublishFailure(void* context, MQTTAsync_failureData* response);  
308 - static void onSubscribeSuccess(void* context, MQTTAsync_successData* response);  
309 - static void onSubscribeFailure(void* context, MQTTAsync_failureData* response);  
310 - static void onUnsubscribeSuccess(void* context, MQTTAsync_successData* response);  
311 - static void onUnsubscribeFailure(void* context, MQTTAsync_failureData* response);  
312 - static int onMessageArrived(void* context, char* topicName, int topicLen, MQTTAsync_message* message);  
313 - static void onDeliveryComplete(void* context, MQTTAsync_token token);  
314 - static void onConnectionLost(void* context, char* cause);  
315 -  
316 - /**  
317 - * @brief Connects the paho logging to the mlogic logging system.  
318 - * This callback is registered the first time a ClientPaho instance is constructed.  
319 - */  
320 - static void onLogPaho(enum MQTTASYNC_TRACE_LEVELS level, char* message);  
321 -  
322 - mutable std::mutex m_mutex;  
323 - std::string m_endpoint;  
324 - std::string m_username;  
325 - std::string m_password;  
326 - std::string m_clientId;  
327 - std::set<MQTTAsync_token> m_pendingOperations;  
328 - std::map<MQTTAsync_token, bool> m_operationResult;  
329 - mutable std::condition_variable m_operationsCompleteCV;  
330 - std::map<std::string, Subscription> m_subscriptions;  
331 - std::map<std::string, Subscription> m_pendingSubscriptions;  
332 - std::map<MQTTAsync_token, std::string> m_subscribeTokenToTopic;  
333 - std::map<MQTTAsync_token, std::string> m_unsubscribeTokenToTopic;  
334 - std::deque<Publish> m_pendingPublishes;  
335 - bool m_processPendingPublishes;  
336 - mutable std::condition_variable m_pendingPublishesReadyCV;  
337 - ::MQTTAsync m_client;  
338 - std::atomic<ConnectionStatus> m_connectionStatus;  
339 - std::function<void(const std::string&, ConnectionStatus)> m_connectionStatusCallback;  
340 - std::function<void(const std::string&, std::int32_t)> m_deliveryCompleteCallback;  
341 - MQTTAsync_token m_lastUnsubscribe; ///< centos7 workaround  
342 - std::unique_ptr<std::promise<void>> m_connectPromise;  
343 - std::unique_ptr<std::promise<void>> m_disconnectPromise;  
344 -  
345 - SynchronizedQueue<std::function<void()>> m_callbackEventQueue;  
346 - std::thread m_workerThread;  
347 -  
348 - static std::atomic_int s_numberOfInstances;  
349 -};  
350 -  
351 -} // End namespace mqtt  
352 -} // End namespace components  
353 -} // End namespace osdev  
354 -  
355 -#endif // OSDEV_COMPONENTS_MQTT_CLIENTPAHO_H  
src/commondefs.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_COMMONDEFS_H  
23 -#define OSDEV_COMPONENTS_MQTT_COMMONDEFS_H  
24 -  
25 -// std  
26 -#include <chrono>  
27 -#include <cstdint>  
28 -#include <map>  
29 -#include <ostream>  
30 -#include <set>  
31 -#include <string>  
32 -#include <vector>  
33 -  
34 -// boost  
35 -#include <boost/lexical_cast.hpp>  
36 -#include <boost/optional.hpp>  
37 -#include <boost/uuid/uuid.hpp>  
38 -#include <boost/uuid/uuid_io.hpp>  
39 -  
40 -#include "utils.h"  
41 -  
42 -  
43 -/// @brief Check if an id is valid  
44 -/// @throws InvalidArgumentException if id is invalid  
45 -#define OSDEV_COMPONENTS_CHECKMQTTID(id) \  
46 - [&] { \  
47 - if (id.is_nil()) { \  
48 - } \  
49 - }()  
50 -  
51 -  
52 -namespace osdev {  
53 -namespace components {  
54 -namespace mqtt {  
55 -  
56 -using MqttId = boost::uuids::uuid;  
57 -using OptionalId = MqttId;  
58 -using MqttIdSet = std::set<MqttId>;  
59 -using MqttIdSetIterator = MqttIdSet::const_iterator;  
60 -using MqttIdSetDelta = std::pair<MqttIdSet, MqttIdSet>;  
61 -using StdTime = std::chrono::system_clock::time_point;  
62 -using OptionalTime = boost::optional<StdTime>;  
63 -using StdTimeVec = std::vector<StdTime>;  
64 -using SequenceNumber = std::uint32_t;  
65 -using OptionalSequenceNumber = boost::optional<SequenceNumber>;  
66 -using CustomField = std::string;  
67 -using CustomFieldCollection = std::vector<CustomField>;  
68 -  
69 -using CountryCodeEnum = std::int32_t;  
70 -  
71 -/**  
72 - * @brief Defines a parsed uri.  
73 - */  
74 -using ParsedUri = std::map<std::string, std::string>;  
75 -  
76 -/**  
77 - * @brief Type for the parsed query part of a uri.  
78 - */  
79 -using ParsedQuery = std::map<std::string, std::string>;  
80 -  
81 -/**  
82 - * @brief Type for the parsed path part of a uri.  
83 - */  
84 -using ParsedPath = std::vector<std::string>;  
85 -  
86 -/**  
87 - * @brief Defines a duration with the granularity of a day in seconds (24 * 60 * 60 = 86400).  
88 - * This duration can be used to create a time_point at midnight of a given DateTime amongst others.  
89 - *  
90 - * The representation is a signed type so that negative durations are also possible.  
91 - */  
92 -using days = std::chrono::duration<std::int32_t, std::ratio<86400>>;  
93 -  
94 -/**  
95 - * @brief Defines a duration with the granularity of a year in seconds. A year is a bit longer than 365 days (365.2425). If a year is  
96 - * subtracted from a date the time part of the new date will therefore differ from the time part of the subtracted from date.  
97 - *  
98 - * The representation is a signed type so that negative durations are also possible.  
99 - */  
100 -using years = std::chrono::duration<std::int32_t, std::ratio<31556952>>; // excactly 365 days would give 31536000  
101 -  
102 -/**  
103 - * A timepoint type that is printed with millisecond resolution.  
104 - */  
105 -struct StdTimeMs  
106 -{  
107 - StdTimeMs(const StdTime& tp)  
108 - : timePoint(tp)  
109 - {  
110 - }  
111 -  
112 - operator StdTime() const { return timePoint; }  
113 -  
114 - StdTime timePoint;  
115 -};  
116 -  
117 -std::ostream& operator<<(std::ostream& os, const StdTimeMs& rhs);  
118 -  
119 -} // End namespace mqtt  
120 -} // End namespace components  
121 -} // End namespace osdev  
122 -  
123 -namespace std {  
124 -  
125 -std::ostream& operator<<(std::ostream& os, const osdev::components::mqtt::StdTime& rhs);  
126 -  
127 -} // End namespace std  
128 -  
129 -#endif // OSDEV_COMPONENTS_MQTT_COMMONDEFS_H  
src/compat-c++14.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_COMPATCXX14  
23 -#define OSDEV_COMPONENTS_COMPATCXX14  
24 -  
25 -#include <memory>  
26 -  
27 -// The below code must be skipped if we use a C++14 or newer compiler  
28 -#if __cplusplus == 201103L  
29 -  
30 -namespace std {  
31 -/// Copied from libstdc++ 4.9.2 bits/unique_ptr.h  
32 -  
33 -template <typename _Tp>  
34 -struct _MakeUniq  
35 -{  
36 - typedef unique_ptr<_Tp> __single_object;  
37 -};  
38 -  
39 -template <typename _Tp>  
40 -struct _MakeUniq<_Tp[]>  
41 -{  
42 - typedef unique_ptr<_Tp[]> __array;  
43 -};  
44 -  
45 -template <typename _Tp, size_t _Bound>  
46 -struct _MakeUniq<_Tp[_Bound]>  
47 -{  
48 - struct __invalid_type  
49 - {  
50 - };  
51 -};  
52 -  
53 -/// std::make_unique for single objects  
54 -template <typename _Tp, typename... _Args>  
55 -inline typename _MakeUniq<_Tp>::__single_object make_unique(_Args&&... __args)  
56 -{  
57 - return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...));  
58 -}  
59 -  
60 -/// std::make_unique for arrays of unknown bound  
61 -template <typename _Tp>  
62 -inline typename _MakeUniq<_Tp>::__array make_unique(size_t __num)  
63 -{  
64 - return unique_ptr<_Tp>(new typename remove_extent<_Tp>::type[__num]());  
65 -}  
66 -  
67 -/// Disable std::make_unique for arrays of known bound  
68 -template <typename _Tp, typename... _Args>  
69 -inline typename _MakeUniq<_Tp>::__invalid_type make_unique(_Args&&...) = delete;  
70 -  
71 -} // End namespace std  
72 -  
73 -#endif // Check for C++14  
74 -  
75 -#endif  
src/compat-chrono.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#include <chrono>  
23 -#include <type_traits>  
24 -  
25 -// function std::chrono::ceil is added in the c++17 standard.  
26 -// Added implementation from https://en.cppreference.com/w/cpp/chrono/duration/ceil  
27 -// to this compatibility header. The header only defines this implementation when  
28 -// the c++ compiler is used with an older standard.  
29 -  
30 -#if !defined __cpp_lib_chrono || __cpp_lib_chrono < 201611  
31 -  
32 -namespace std {  
33 -namespace chrono {  
34 -  
35 -template <class T>  
36 -struct is_duration : std::false_type  
37 -{  
38 -};  
39 -template <class Rep, class Period>  
40 -struct is_duration<  
41 - std::chrono::duration<Rep, Period>> : std::true_type  
42 -{  
43 -};  
44 -  
45 -template <class To, class Rep, class Period,  
46 - class = typename enable_if<is_duration<To>{}>::type>  
47 -To ceil(const std::chrono::duration<Rep, Period>& d)  
48 -{  
49 - To t = std::chrono::duration_cast<To>(d);  
50 - if (t < d)  
51 - {  
52 - return t + To{ 1 };  
53 - }  
54 -  
55 - // or else...  
56 - return t;  
57 -}  
58 -  
59 -} // End namespace chrono  
60 -} // End namespace std  
61 -  
62 -#endif  
src/compiletimedigits.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_COMPILETIMEDIGITS_H  
23 -#define OSDEV_COMPONENTS_MQTT_COMPILETIMEDIGITS_H  
24 -  
25 -// std  
26 -#include <string>  
27 -  
28 -#include "compiletimestring.h"  
29 -  
30 -namespace osdev {  
31 -namespace components {  
32 -namespace mqtt {  
33 -  
34 -/**  
35 - * @brief Calculate the number of digits needed to represent a given value in a given base.  
36 - * @tparam B The base to use.  
37 - * @param value The value to represent.  
38 - * @return The number of digits.  
39 - */  
40 -template <unsigned B>  
41 -constexpr std::size_t numberOfDigits(unsigned value) noexcept  
42 -{  
43 - static_assert(B > 0, "base must be larger than zero");  
44 - return (value / B) == 0 ? 1 : (1 + numberOfDigits<B>(value / B));  
45 -}  
46 -  
47 -/**  
48 - * @return stringified digit that represents the given single digit value.  
49 - * @note Values can range from 0 to 37 inclusive which maps on 0-9A-Z.  
50 - */  
51 -template <unsigned value>  
52 -constexpr char digit() noexcept  
53 -{  
54 - static_assert(value <= 37, "Value must lie between 0 and 37 both inclusive");  
55 - return (value < 10 ? '0' + static_cast<char>(value) : 'A' + static_cast<char>(value) - 10);  
56 -}  
57 -  
58 -/**  
59 - * @brief Recursive template definition that is used to determine the value of a given number N in a given base B.  
60 - * @tparam N The number to obtain the representation for.  
61 - * @tparam B The base to use.  
62 - * @tparam Len The length of the representation including the 0 terminator.  
63 - * If not provided the length is calculated on first instantiation of this template.  
64 - * @tparam remains Empty parameter pack on first instantiation. Will be filled further by every following instantiation.  
65 - */  
66 -template <unsigned N, unsigned B, std::size_t Len = numberOfDigits<B>(N) + 1, unsigned... remains>  
67 -struct Digits  
68 -{  
69 -  
70 - static constexpr auto create() noexcept -> std::array<char, Len>  
71 - {  
72 - static_assert(B > 0, "base must be larger than zero");  
73 - return Digits<N / B, B, Len, digit<N % B>(), remains...>::create();  
74 - }  
75 -};  
76 -  
77 -/**  
78 - * @brief Termination template that will return the actual hex digit array that represents the given value.  
79 - * @tparam B The base to use.  
80 - * @tparam Len The length of the hexadecimal representation including 0 terminator.  
81 - * @tparam remains Parameter pack that contains the hexadecimal character representations.  
82 - */  
83 -template <unsigned B, std::size_t Len, unsigned... remains>  
84 -struct Digits<0, B, Len, remains...>  
85 -{  
86 -  
87 - static constexpr auto create() noexcept -> std::array<char, Len>  
88 - {  
89 - static_assert(sizeof...(remains) + 1 == Len, "Parameter 'Len' must be equal to the length of the parameter pack 'remains' including the termination zero");  
90 - return std::array<char, Len>{ { remains..., 0 } };  
91 - }  
92 -};  
93 -  
94 -/**  
95 - * @brief Digits builder can be used in combination with the compiletime_string.  
96 - * @tparam N The number to obtain the compile time string representation for.  
97 - * @tparam B The base to use (up to 37).  
98 - * This template struct defines a produce() method and the return type of that method.  
99 - */  
100 -template <unsigned N, unsigned B>  
101 -struct ProduceDigits  
102 -{  
103 - /**  
104 - * @brief Return type definition of the produce method.  
105 - */  
106 - using return_t = std::array<char, numberOfDigits<B>(N) + 1>;  
107 -  
108 - /**  
109 - * @brief Produce the actual representation.  
110 - */  
111 - static constexpr return_t produce() noexcept  
112 - {  
113 - return Digits<N, B>::create();  
114 - }  
115 -};  
116 -  
117 -} // End namespace mqtt  
118 -} // End namespace components  
119 -} // End namespace osdev  
120 -  
121 -#endif // OSDEV_COMPONENTS_MQTT_COMPILETIMEDIGITS_H  
src/compiletimestring.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_COMPILETIMESTRING_H  
23 -#define OSDEV_COMPONENTS_MQTT_COMPILETIMESTRING_H  
24 -  
25 -/// @file  
26 -///  
27 -/// Support for compiletime string building.  
28 -///  
29 -/// In some cases it is necessary to embed string messages as read only string literals  
30 -/// so that they can be used in low memory conditions for example.  
31 -/// This header defines two macro's that can be used to build managed string literals.  
32 -/// These managed string literals can be concatenated and searched at compiletime.  
33 -/// When the compiler is done with this code only the embedded string literal that are  
34 -/// used by normal expressions remain in the binary.  
35 -/// The implementation is a mix of meta template programming and the use of constexpr  
36 -/// expressions and is based on an idea found on <a href="http://stackoverflow.com/a/15912824">stackoverflow</a>.  
37 -/// This code is meant to handle small strings (up to say 100 characters). Larger strings can trigger the maximum  
38 -/// template recursion depth of the compiler (-ftemplate-depth). This depth is set at 900. So in principle strings  
39 -/// of 900 characters can be handled. However this is very inefficient and will prolong compiletime severly.  
40 -///  
41 -/// Here follows an example of how this code can be used.  
42 -/// @code  
43 -/// auto str1 = OSDEV_COMPONENTS_CSTRING("This is a test");  
44 -/// auto str2 = OSDEV_COMPONENTS_CSTRING(" with concatenation");  
45 -/// auto str3 = str1 + str2;  
46 -/// const char* s = str3.chars;  
47 -/// @endcode  
48 -/// str3.chars contains the compiletime concatenated string.  
49 -///  
50 -/// When examing the binary one will see that it contains the null terminated string literal  
51 -/// @code  
52 -/// This is a test with concatenation^@  
53 -/// @endcode  
54 -/// The str1 and str2 literals are discarded since they are never used in a non compiletime way.  
55 -/// @note This code is not meant to handle string literals with internal \0 characters. Beware!  
56 -  
57 -#include <limits>  
58 -  
59 -#include "metaprogrammingdefs.h"  
60 -  
61 -/// @brief Build a managed substring string literal from a string literal input  
62 -/// The strings are build compile time.  
63 -/// The upper bound is one past the last character that the caller is interested in.  
64 -#define OSDEV_COMPONENTS_CSTRING_BOUNDED(string_literal, lower, upper) \  
65 - [] { \  
66 - constexpr std::size_t lb = (lower); \  
67 - constexpr std::size_t ub = (upper); \  
68 - static_assert(lb <= ub, "lower bound must be smaller than or equal to upper bound"); \  
69 - static_assert(ub < sizeof(string_literal), \  
70 - "upper bound must be smaller than or equal to the length of the string"); \  
71 - struct constexpr_string_type \  
72 - { \  
73 - const char* chars = string_literal; \  
74 - }; \  
75 - return typename osdev::components::mqtt::apply_bounded_range<lb, ub, \  
76 - osdev::components::mqtt::string_builder<constexpr_string_type>::template produce>::result{}; \  
77 - }()  
78 -  
79 -/// @brief Build a managed string literal from a string literal input  
80 -#define OSDEV_COMPONENTS_CSTRING(string_literal) \  
81 - OSDEV_COMPONENTS_CSTRING_BOUNDED(string_literal, 0, sizeof(string_literal) - 1)  
82 -  
83 -namespace osdev {  
84 -namespace components {  
85 -namespace mqtt {  
86 -  
87 -/// @brief Managed string literal.  
88 -/// This class is used to hold string literals at compile time.  
89 -template <char... str>  
90 -struct compiletime_string  
91 -{  
92 - /// @brief Declaration of the string  
93 - static constexpr const char chars[sizeof...(str) + 1] = { str..., '\0' };  
94 -};  
95 -  
96 -/// @brief Definition of the string  
97 -template <char... str>  
98 -constexpr const char compiletime_string<str...>::chars[sizeof...(str) + 1];  
99 -  
100 -/// @brief Managed string literal builder.  
101 -/// This class is used to build string literals at compile time.  
102 -template <typename lambda_str_type>  
103 -struct string_builder  
104 -{  
105 - /// @brief maps indices list on the char array  
106 - template <std::size_t... indices>  
107 - struct produce  
108 - {  
109 - typedef compiletime_string<lambda_str_type{}.chars[indices]...> result;  
110 - };  
111 -};  
112 -  
113 -/// @brief Adapter for coupling other producers to string_builder.  
114 -/// tparam T The type of producer to adapt.  
115 -/// @note The adapter must define its return type as return_t and provide a static method produce() which produces the result.  
116 -/// The return type must be a kind of array type of chars (char[len], std::array<char,len>, etc).  
117 -template <typename T>  
118 -struct adapt_for_string_builder  
119 -{  
120 - static constexpr typename T::return_t chars = T::produce();  
121 -};  
122 -  
123 -/// @brief Concatenate two managed string literals  
124 -/// The literals are packed in a variadic template.  
125 -/// These templates are formed by the MLOGIC_COMMON_CSTRING* macro's  
126 -/// The concatenation is done at compiletime.  
127 -template <char... str0, char... str1>  
128 -compiletime_string<str0..., str1...> operator+(compiletime_string<str0...>, compiletime_string<str1...>)  
129 -{  
130 - return {};  
131 -}  
132 -  
133 -/// @brief Search for a character in a string literal from the right side.  
134 -/// The character index is returned relative to the left side.  
135 -/// If the character is not found a std::size_t(-1) is returned.  
136 -/// The default search starts at the end of the string. The index  
137 -/// can be given to start the search at another point in the string.  
138 -/// The index is given as nr of characters from the right end side of  
139 -/// the string. To proceed with a search see following example.  
140 -/// @code  
141 -/// constexpr const char s[] = "This is a test";  
142 -/// constexpr std::size_t index = osdev_components::mqtt::rfind(s, 'i'); // gives 5  
143 -/// static_assert(index == 5, "");  
144 -/// constexpr std::size_t index2 = osdev::components::mqtt::rfind(s, 'i', sizeof(s) - index); // gives 2  
145 -/// static_assert(index2 == 2, "");  
146 -/// @endcode  
147 -/// This function should only be used at compile time!  
148 -template <std::size_t N>  
149 -constexpr std::size_t rfind(const char (&str)[N], char c, std::size_t index = 0)  
150 -{  
151 - return index >= N ? std::numeric_limits<std::size_t>::max() : str[N - index - 1] == c ? N - index - 1 : rfind(str, c, index + 1);  
152 -}  
153 -  
154 -} // End namespace mqtt  
155 -} // End namespace components  
156 -} // End namespace osdev  
157 -  
158 -#endif // OSDEV_COMPONENTS_MQTT_COMPILETIMESTRING_H  
src/connectionstatus.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_CONNECTIONSTATUS_H  
23 -#define OSDEV_COMPONENTS_MQTT_CONNECTIONSTATUS_H  
24 -  
25 -// std  
26 -#include <ostream>  
27 -  
28 -namespace osdev {  
29 -namespace components {  
30 -namespace mqtt {  
31 -  
32 -/*!  
33 - * \brief Enumeration for MQTT connection Status  
34 - */  
35 -enum class ConnectionStatus  
36 -{  
37 - Disconnected, ///< Client is disconnected.  
38 - DisconnectInProgress, ///< Client is being disconnected.  
39 - ConnectInProgress, ///< Client is being connected.  
40 - ReconnectInProgress, ///< Client tries to reconnect.  
41 - Connected, ///< Client is connected.  
42 -};  
43 -  
44 -/*!  
45 - * \brief Stream operator for the connection status  
46 - */  
47 -std::ostream& operator<<(std::ostream &os, ConnectionStatus rhs);  
48 -  
49 -} // End namespace mqtt  
50 -} // End namespace components  
51 -} // End namespace osdev  
52 -  
53 -#endif // OSDEV_COMPONENTS_MQTT_CONNECTIONSTATUS_H  
src/credentials.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_CREDENTIALS_H  
23 -#define OSDEV_COMPONENTS_MQTT_CREDENTIALS_H  
24 -  
25 -// std  
26 -#include <string>  
27 -  
28 -namespace osdev {  
29 -namespace components {  
30 -namespace mqtt {  
31 -  
32 -/*!  
33 - * \brief Class that holds user credentials  
34 - */  
35 -class Credentials  
36 -{  
37 -public:  
38 - /*!  
39 - * \brief Default CTor, empty credentials  
40 - */  
41 - Credentials();  
42 -  
43 - /*!  
44 - * \brief Constructor for username/password credentials  
45 - * \param username - The username  
46 - * \param password - The password  
47 - */  
48 - Credentials(const std::string &username, const std::string &password);  
49 -  
50 - const std::string& username() const { return m_username; }  
51 - const std::string& password() const { return m_password; }  
52 -private:  
53 - std::string m_username;  
54 - std::string m_password;  
55 -};  
56 -  
57 -} // End namespace mqtt  
58 -} // End namespace components  
59 -} // End namespace osdev  
60 -  
61 -#endif // OSDEV_COMPONENTS_MQTT_CREDENTIALS_H  
src/date.h deleted
1 -#ifndef DATE_H  
2 -#define DATE_H  
3 -  
4 -// The MIT License (MIT)  
5 -//  
6 -// Copyright (c) 2015, 2016, 2017 Howard Hinnant  
7 -// Copyright (c) 2016 Adrian Colomitchi  
8 -// Copyright (c) 2017 Florian Dang  
9 -// Copyright (c) 2017 Paul Thompson  
10 -// Copyright (c) 2018, 2019 Tomasz Kamiล„ski  
11 -// Copyright (c) 2019 Jiangang Zhuang  
12 -//  
13 -// Permission is hereby granted, free of charge, to any person obtaining a copy  
14 -// of this software and associated documentation files (the "Software"), to deal  
15 -// in the Software without restriction, including without limitation the rights  
16 -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
17 -// copies of the Software, and to permit persons to whom the Software is  
18 -// furnished to do so, subject to the following conditions:  
19 -//  
20 -// The above copyright notice and this permission notice shall be included in all  
21 -// copies or substantial portions of the Software.  
22 -//  
23 -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
24 -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
25 -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
26 -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
27 -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
28 -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  
29 -// SOFTWARE.  
30 -//  
31 -// Our apologies. When the previous paragraph was written, lowercase had not yet  
32 -// been invented (that would involve another several millennia of evolution).  
33 -// We did not mean to shout.  
34 -  
35 -#ifndef HAS_STRING_VIEW  
36 -# if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)  
37 -# define HAS_STRING_VIEW 1  
38 -# else  
39 -# define HAS_STRING_VIEW 0  
40 -# endif  
41 -#endif // HAS_STRING_VIEW  
42 -  
43 -#include <cassert>  
44 -#include <algorithm>  
45 -#include <cctype>  
46 -#include <chrono>  
47 -#include <climits>  
48 -#include <cmath>  
49 -#include <cstddef>  
50 -#include <cstdint>  
51 -#include <cstdlib>  
52 -#include <ctime>  
53 -#include <ios>  
54 -#include <istream>  
55 -#include <iterator>  
56 -#include <limits>  
57 -#include <locale>  
58 -#include <memory>  
59 -#include <ostream>  
60 -#include <ratio>  
61 -#include <sstream>  
62 -#include <stdexcept>  
63 -#include <string>  
64 -#if HAS_STRING_VIEW  
65 -# include <string_view>  
66 -#endif  
67 -#include <utility>  
68 -#include <type_traits>  
69 -  
70 -#ifdef __GNUC__  
71 -# pragma GCC diagnostic push  
72 -# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7)  
73 -# pragma GCC diagnostic ignored "-Wpedantic"  
74 -# endif  
75 -# if __GNUC__ < 5  
76 - // GCC 4.9 Bug 61489 Wrong warning with -Wmissing-field-initializers  
77 -# pragma GCC diagnostic ignored "-Wmissing-field-initializers"  
78 -# endif  
79 -#endif  
80 -  
81 -#ifdef _MSC_VER  
82 -# pragma warning(push)  
83 -// warning C4127: conditional expression is constant  
84 -# pragma warning(disable : 4127)  
85 -#endif  
86 -  
87 -namespace date  
88 -{  
89 -  
90 -//---------------+  
91 -// Configuration |  
92 -//---------------+  
93 -  
94 -#ifndef ONLY_C_LOCALE  
95 -# define ONLY_C_LOCALE 0  
96 -#endif  
97 -  
98 -#if defined(_MSC_VER) && (!defined(__clang__) || (_MSC_VER < 1910))  
99 -// MSVC  
100 -# ifndef _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING  
101 -# define _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING  
102 -# endif  
103 -# if _MSC_VER < 1910  
104 -// before VS2017  
105 -# define CONSTDATA const  
106 -# define CONSTCD11  
107 -# define CONSTCD14  
108 -# define NOEXCEPT _NOEXCEPT  
109 -# else  
110 -// VS2017 and later  
111 -# define CONSTDATA constexpr const  
112 -# define CONSTCD11 constexpr  
113 -# define CONSTCD14 constexpr  
114 -# define NOEXCEPT noexcept  
115 -# endif  
116 -  
117 -#elif defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x5150  
118 -// Oracle Developer Studio 12.6 and earlier  
119 -# define CONSTDATA constexpr const  
120 -# define CONSTCD11 constexpr  
121 -# define CONSTCD14  
122 -# define NOEXCEPT noexcept  
123 -  
124 -#elif __cplusplus >= 201402  
125 -// C++14  
126 -# define CONSTDATA constexpr const  
127 -# define CONSTCD11 constexpr  
128 -# define CONSTCD14 constexpr  
129 -# define NOEXCEPT noexcept  
130 -#else  
131 -// C++11  
132 -# define CONSTDATA constexpr const  
133 -# define CONSTCD11 constexpr  
134 -# define CONSTCD14  
135 -# define NOEXCEPT noexcept  
136 -#endif  
137 -  
138 -#ifndef HAS_UNCAUGHT_EXCEPTIONS  
139 -# if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)  
140 -# define HAS_UNCAUGHT_EXCEPTIONS 1  
141 -# else  
142 -# define HAS_UNCAUGHT_EXCEPTIONS 0  
143 -# endif  
144 -#endif // HAS_UNCAUGHT_EXCEPTIONS  
145 -  
146 -#ifndef HAS_VOID_T  
147 -# if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)  
148 -# define HAS_VOID_T 1  
149 -# else  
150 -# define HAS_VOID_T 0  
151 -# endif  
152 -#endif // HAS_VOID_T  
153 -  
154 -// Protect from Oracle sun macro  
155 -#ifdef sun  
156 -# undef sun  
157 -#endif  
158 -  
159 -// Work around for a NVCC compiler bug which causes it to fail  
160 -// to compile std::ratio_{multiply,divide} when used directly  
161 -// in the std::chrono::duration template instantiations below  
162 -namespace detail {  
163 -template <typename R1, typename R2>  
164 -using ratio_multiply = decltype(std::ratio_multiply<R1, R2>{});  
165 -  
166 -template <typename R1, typename R2>  
167 -using ratio_divide = decltype(std::ratio_divide<R1, R2>{});  
168 -} // namespace detail  
169 -  
170 -//-----------+  
171 -// Interface |  
172 -//-----------+  
173 -  
174 -// durations  
175 -  
176 -using days = std::chrono::duration  
177 - <int, detail::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;  
178 -  
179 -using weeks = std::chrono::duration  
180 - <int, detail::ratio_multiply<std::ratio<7>, days::period>>;  
181 -  
182 -using years = std::chrono::duration  
183 - <int, detail::ratio_multiply<std::ratio<146097, 400>, days::period>>;  
184 -  
185 -using months = std::chrono::duration  
186 - <int, detail::ratio_divide<years::period, std::ratio<12>>>;  
187 -  
188 -// time_point  
189 -  
190 -template <class Duration>  
191 - using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;  
192 -  
193 -using sys_days = sys_time<days>;  
194 -using sys_seconds = sys_time<std::chrono::seconds>;  
195 -  
196 -struct local_t {};  
197 -  
198 -template <class Duration>  
199 - using local_time = std::chrono::time_point<local_t, Duration>;  
200 -  
201 -using local_seconds = local_time<std::chrono::seconds>;  
202 -using local_days = local_time<days>;  
203 -  
204 -// types  
205 -  
206 -struct last_spec  
207 -{  
208 - explicit last_spec() = default;  
209 -};  
210 -  
211 -class day;  
212 -class month;  
213 -class year;  
214 -  
215 -class weekday;  
216 -class weekday_indexed;  
217 -class weekday_last;  
218 -  
219 -class month_day;  
220 -class month_day_last;  
221 -class month_weekday;  
222 -class month_weekday_last;  
223 -  
224 -class year_month;  
225 -  
226 -class year_month_day;  
227 -class year_month_day_last;  
228 -class year_month_weekday;  
229 -class year_month_weekday_last;  
230 -  
231 -// date composition operators  
232 -  
233 -CONSTCD11 year_month operator/(const year& y, const month& m) NOEXCEPT;  
234 -CONSTCD11 year_month operator/(const year& y, int m) NOEXCEPT;  
235 -  
236 -CONSTCD11 month_day operator/(const day& d, const month& m) NOEXCEPT;  
237 -CONSTCD11 month_day operator/(const day& d, int m) NOEXCEPT;  
238 -CONSTCD11 month_day operator/(const month& m, const day& d) NOEXCEPT;  
239 -CONSTCD11 month_day operator/(const month& m, int d) NOEXCEPT;  
240 -CONSTCD11 month_day operator/(int m, const day& d) NOEXCEPT;  
241 -  
242 -CONSTCD11 month_day_last operator/(const month& m, last_spec) NOEXCEPT;  
243 -CONSTCD11 month_day_last operator/(int m, last_spec) NOEXCEPT;  
244 -CONSTCD11 month_day_last operator/(last_spec, const month& m) NOEXCEPT;  
245 -CONSTCD11 month_day_last operator/(last_spec, int m) NOEXCEPT;  
246 -  
247 -CONSTCD11 month_weekday operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT;  
248 -CONSTCD11 month_weekday operator/(int m, const weekday_indexed& wdi) NOEXCEPT;  
249 -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT;  
250 -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, int m) NOEXCEPT;  
251 -  
252 -CONSTCD11 month_weekday_last operator/(const month& m, const weekday_last& wdl) NOEXCEPT;  
253 -CONSTCD11 month_weekday_last operator/(int m, const weekday_last& wdl) NOEXCEPT;  
254 -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, const month& m) NOEXCEPT;  
255 -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, int m) NOEXCEPT;  
256 -  
257 -CONSTCD11 year_month_day operator/(const year_month& ym, const day& d) NOEXCEPT;  
258 -CONSTCD11 year_month_day operator/(const year_month& ym, int d) NOEXCEPT;  
259 -CONSTCD11 year_month_day operator/(const year& y, const month_day& md) NOEXCEPT;  
260 -CONSTCD11 year_month_day operator/(int y, const month_day& md) NOEXCEPT;  
261 -CONSTCD11 year_month_day operator/(const month_day& md, const year& y) NOEXCEPT;  
262 -CONSTCD11 year_month_day operator/(const month_day& md, int y) NOEXCEPT;  
263 -  
264 -CONSTCD11  
265 - year_month_day_last operator/(const year_month& ym, last_spec) NOEXCEPT;  
266 -CONSTCD11  
267 - year_month_day_last operator/(const year& y, const month_day_last& mdl) NOEXCEPT;  
268 -CONSTCD11  
269 - year_month_day_last operator/(int y, const month_day_last& mdl) NOEXCEPT;  
270 -CONSTCD11  
271 - year_month_day_last operator/(const month_day_last& mdl, const year& y) NOEXCEPT;  
272 -CONSTCD11  
273 - year_month_day_last operator/(const month_day_last& mdl, int y) NOEXCEPT;  
274 -  
275 -CONSTCD11  
276 -year_month_weekday  
277 -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT;  
278 -  
279 -CONSTCD11  
280 -year_month_weekday  
281 -operator/(const year& y, const month_weekday& mwd) NOEXCEPT;  
282 -  
283 -CONSTCD11  
284 -year_month_weekday  
285 -operator/(int y, const month_weekday& mwd) NOEXCEPT;  
286 -  
287 -CONSTCD11  
288 -year_month_weekday  
289 -operator/(const month_weekday& mwd, const year& y) NOEXCEPT;  
290 -  
291 -CONSTCD11  
292 -year_month_weekday  
293 -operator/(const month_weekday& mwd, int y) NOEXCEPT;  
294 -  
295 -CONSTCD11  
296 -year_month_weekday_last  
297 -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT;  
298 -  
299 -CONSTCD11  
300 -year_month_weekday_last  
301 -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT;  
302 -  
303 -CONSTCD11  
304 -year_month_weekday_last  
305 -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT;  
306 -  
307 -CONSTCD11  
308 -year_month_weekday_last  
309 -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT;  
310 -  
311 -CONSTCD11  
312 -year_month_weekday_last  
313 -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT;  
314 -  
315 -// Detailed interface  
316 -  
317 -// day  
318 -  
319 -class day  
320 -{  
321 - unsigned char d_;  
322 -  
323 -public:  
324 - day() = default;  
325 - explicit CONSTCD11 day(unsigned d) NOEXCEPT;  
326 -  
327 - CONSTCD14 day& operator++() NOEXCEPT;  
328 - CONSTCD14 day operator++(int) NOEXCEPT;  
329 - CONSTCD14 day& operator--() NOEXCEPT;  
330 - CONSTCD14 day operator--(int) NOEXCEPT;  
331 -  
332 - CONSTCD14 day& operator+=(const days& d) NOEXCEPT;  
333 - CONSTCD14 day& operator-=(const days& d) NOEXCEPT;  
334 -  
335 - CONSTCD11 explicit operator unsigned() const NOEXCEPT;  
336 - CONSTCD11 bool ok() const NOEXCEPT;  
337 -};  
338 -  
339 -CONSTCD11 bool operator==(const day& x, const day& y) NOEXCEPT;  
340 -CONSTCD11 bool operator!=(const day& x, const day& y) NOEXCEPT;  
341 -CONSTCD11 bool operator< (const day& x, const day& y) NOEXCEPT;  
342 -CONSTCD11 bool operator> (const day& x, const day& y) NOEXCEPT;  
343 -CONSTCD11 bool operator<=(const day& x, const day& y) NOEXCEPT;  
344 -CONSTCD11 bool operator>=(const day& x, const day& y) NOEXCEPT;  
345 -  
346 -CONSTCD11 day operator+(const day& x, const days& y) NOEXCEPT;  
347 -CONSTCD11 day operator+(const days& x, const day& y) NOEXCEPT;  
348 -CONSTCD11 day operator-(const day& x, const days& y) NOEXCEPT;  
349 -CONSTCD11 days operator-(const day& x, const day& y) NOEXCEPT;  
350 -  
351 -template<class CharT, class Traits>  
352 -std::basic_ostream<CharT, Traits>&  
353 -operator<<(std::basic_ostream<CharT, Traits>& os, const day& d);  
354 -  
355 -// month  
356 -  
357 -class month  
358 -{  
359 - unsigned char m_;  
360 -  
361 -public:  
362 - month() = default;  
363 - explicit CONSTCD11 month(unsigned m) NOEXCEPT;  
364 -  
365 - CONSTCD14 month& operator++() NOEXCEPT;  
366 - CONSTCD14 month operator++(int) NOEXCEPT;  
367 - CONSTCD14 month& operator--() NOEXCEPT;  
368 - CONSTCD14 month operator--(int) NOEXCEPT;  
369 -  
370 - CONSTCD14 month& operator+=(const months& m) NOEXCEPT;  
371 - CONSTCD14 month& operator-=(const months& m) NOEXCEPT;  
372 -  
373 - CONSTCD11 explicit operator unsigned() const NOEXCEPT;  
374 - CONSTCD11 bool ok() const NOEXCEPT;  
375 -};  
376 -  
377 -CONSTCD11 bool operator==(const month& x, const month& y) NOEXCEPT;  
378 -CONSTCD11 bool operator!=(const month& x, const month& y) NOEXCEPT;  
379 -CONSTCD11 bool operator< (const month& x, const month& y) NOEXCEPT;  
380 -CONSTCD11 bool operator> (const month& x, const month& y) NOEXCEPT;  
381 -CONSTCD11 bool operator<=(const month& x, const month& y) NOEXCEPT;  
382 -CONSTCD11 bool operator>=(const month& x, const month& y) NOEXCEPT;  
383 -  
384 -CONSTCD14 month operator+(const month& x, const months& y) NOEXCEPT;  
385 -CONSTCD14 month operator+(const months& x, const month& y) NOEXCEPT;  
386 -CONSTCD14 month operator-(const month& x, const months& y) NOEXCEPT;  
387 -CONSTCD14 months operator-(const month& x, const month& y) NOEXCEPT;  
388 -  
389 -template<class CharT, class Traits>  
390 -std::basic_ostream<CharT, Traits>&  
391 -operator<<(std::basic_ostream<CharT, Traits>& os, const month& m);  
392 -  
393 -// year  
394 -  
395 -class year  
396 -{  
397 - short y_;  
398 -  
399 -public:  
400 - year() = default;  
401 - explicit CONSTCD11 year(int y) NOEXCEPT;  
402 -  
403 - CONSTCD14 year& operator++() NOEXCEPT;  
404 - CONSTCD14 year operator++(int) NOEXCEPT;  
405 - CONSTCD14 year& operator--() NOEXCEPT;  
406 - CONSTCD14 year operator--(int) NOEXCEPT;  
407 -  
408 - CONSTCD14 year& operator+=(const years& y) NOEXCEPT;  
409 - CONSTCD14 year& operator-=(const years& y) NOEXCEPT;  
410 -  
411 - CONSTCD11 year operator-() const NOEXCEPT;  
412 - CONSTCD11 year operator+() const NOEXCEPT;  
413 -  
414 - CONSTCD11 bool is_leap() const NOEXCEPT;  
415 -  
416 - CONSTCD11 explicit operator int() const NOEXCEPT;  
417 - CONSTCD11 bool ok() const NOEXCEPT;  
418 -  
419 - static CONSTCD11 year min() NOEXCEPT { return year{-32767}; }  
420 - static CONSTCD11 year max() NOEXCEPT { return year{32767}; }  
421 -};  
422 -  
423 -CONSTCD11 bool operator==(const year& x, const year& y) NOEXCEPT;  
424 -CONSTCD11 bool operator!=(const year& x, const year& y) NOEXCEPT;  
425 -CONSTCD11 bool operator< (const year& x, const year& y) NOEXCEPT;  
426 -CONSTCD11 bool operator> (const year& x, const year& y) NOEXCEPT;  
427 -CONSTCD11 bool operator<=(const year& x, const year& y) NOEXCEPT;  
428 -CONSTCD11 bool operator>=(const year& x, const year& y) NOEXCEPT;  
429 -  
430 -CONSTCD11 year operator+(const year& x, const years& y) NOEXCEPT;  
431 -CONSTCD11 year operator+(const years& x, const year& y) NOEXCEPT;  
432 -CONSTCD11 year operator-(const year& x, const years& y) NOEXCEPT;  
433 -CONSTCD11 years operator-(const year& x, const year& y) NOEXCEPT;  
434 -  
435 -template<class CharT, class Traits>  
436 -std::basic_ostream<CharT, Traits>&  
437 -operator<<(std::basic_ostream<CharT, Traits>& os, const year& y);  
438 -  
439 -// weekday  
440 -  
441 -class weekday  
442 -{  
443 - unsigned char wd_;  
444 -public:  
445 - weekday() = default;  
446 - explicit CONSTCD11 weekday(unsigned wd) NOEXCEPT;  
447 - CONSTCD14 weekday(const sys_days& dp) NOEXCEPT;  
448 - CONSTCD14 explicit weekday(const local_days& dp) NOEXCEPT;  
449 -  
450 - CONSTCD14 weekday& operator++() NOEXCEPT;  
451 - CONSTCD14 weekday operator++(int) NOEXCEPT;  
452 - CONSTCD14 weekday& operator--() NOEXCEPT;  
453 - CONSTCD14 weekday operator--(int) NOEXCEPT;  
454 -  
455 - CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT;  
456 - CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT;  
457 -  
458 - CONSTCD11 bool ok() const NOEXCEPT;  
459 -  
460 - CONSTCD11 unsigned c_encoding() const NOEXCEPT;  
461 - CONSTCD11 unsigned iso_encoding() const NOEXCEPT;  
462 -  
463 - CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT;  
464 - CONSTCD11 weekday_last operator[](last_spec) const NOEXCEPT;  
465 -  
466 -private:  
467 - static CONSTCD14 unsigned char weekday_from_days(int z) NOEXCEPT;  
468 -  
469 - friend CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT;  
470 - friend CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT;  
471 - friend CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT;  
472 - template<class CharT, class Traits>  
473 - friend std::basic_ostream<CharT, Traits>&  
474 - operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd);  
475 - friend class weekday_indexed;  
476 -};  
477 -  
478 -CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT;  
479 -CONSTCD11 bool operator!=(const weekday& x, const weekday& y) NOEXCEPT;  
480 -  
481 -CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT;  
482 -CONSTCD14 weekday operator+(const days& x, const weekday& y) NOEXCEPT;  
483 -CONSTCD14 weekday operator-(const weekday& x, const days& y) NOEXCEPT;  
484 -CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT;  
485 -  
486 -template<class CharT, class Traits>  
487 -std::basic_ostream<CharT, Traits>&  
488 -operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd);  
489 -  
490 -// weekday_indexed  
491 -  
492 -class weekday_indexed  
493 -{  
494 - unsigned char wd_ : 4;  
495 - unsigned char index_ : 4;  
496 -  
497 -public:  
498 - weekday_indexed() = default;  
499 - CONSTCD11 weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT;  
500 -  
501 - CONSTCD11 date::weekday weekday() const NOEXCEPT;  
502 - CONSTCD11 unsigned index() const NOEXCEPT;  
503 - CONSTCD11 bool ok() const NOEXCEPT;  
504 -};  
505 -  
506 -CONSTCD11 bool operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT;  
507 -CONSTCD11 bool operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT;  
508 -  
509 -template<class CharT, class Traits>  
510 -std::basic_ostream<CharT, Traits>&  
511 -operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi);  
512 -  
513 -// weekday_last  
514 -  
515 -class weekday_last  
516 -{  
517 - date::weekday wd_;  
518 -  
519 -public:  
520 - explicit CONSTCD11 weekday_last(const date::weekday& wd) NOEXCEPT;  
521 -  
522 - CONSTCD11 date::weekday weekday() const NOEXCEPT;  
523 - CONSTCD11 bool ok() const NOEXCEPT;  
524 -};  
525 -  
526 -CONSTCD11 bool operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT;  
527 -CONSTCD11 bool operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT;  
528 -  
529 -template<class CharT, class Traits>  
530 -std::basic_ostream<CharT, Traits>&  
531 -operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl);  
532 -  
533 -namespace detail  
534 -{  
535 -  
536 -struct unspecified_month_disambiguator {};  
537 -  
538 -} // namespace detail  
539 -  
540 -// year_month  
541 -  
542 -class year_month  
543 -{  
544 - date::year y_;  
545 - date::month m_;  
546 -  
547 -public:  
548 - year_month() = default;  
549 - CONSTCD11 year_month(const date::year& y, const date::month& m) NOEXCEPT;  
550 -  
551 - CONSTCD11 date::year year() const NOEXCEPT;  
552 - CONSTCD11 date::month month() const NOEXCEPT;  
553 -  
554 - template<class = detail::unspecified_month_disambiguator>  
555 - CONSTCD14 year_month& operator+=(const months& dm) NOEXCEPT;  
556 - template<class = detail::unspecified_month_disambiguator>  
557 - CONSTCD14 year_month& operator-=(const months& dm) NOEXCEPT;  
558 - CONSTCD14 year_month& operator+=(const years& dy) NOEXCEPT;  
559 - CONSTCD14 year_month& operator-=(const years& dy) NOEXCEPT;  
560 -  
561 - CONSTCD11 bool ok() const NOEXCEPT;  
562 -};  
563 -  
564 -CONSTCD11 bool operator==(const year_month& x, const year_month& y) NOEXCEPT;  
565 -CONSTCD11 bool operator!=(const year_month& x, const year_month& y) NOEXCEPT;  
566 -CONSTCD11 bool operator< (const year_month& x, const year_month& y) NOEXCEPT;  
567 -CONSTCD11 bool operator> (const year_month& x, const year_month& y) NOEXCEPT;  
568 -CONSTCD11 bool operator<=(const year_month& x, const year_month& y) NOEXCEPT;  
569 -CONSTCD11 bool operator>=(const year_month& x, const year_month& y) NOEXCEPT;  
570 -  
571 -template<class = detail::unspecified_month_disambiguator>  
572 -CONSTCD14 year_month operator+(const year_month& ym, const months& dm) NOEXCEPT;  
573 -template<class = detail::unspecified_month_disambiguator>  
574 -CONSTCD14 year_month operator+(const months& dm, const year_month& ym) NOEXCEPT;  
575 -template<class = detail::unspecified_month_disambiguator>  
576 -CONSTCD14 year_month operator-(const year_month& ym, const months& dm) NOEXCEPT;  
577 -  
578 -CONSTCD11 months operator-(const year_month& x, const year_month& y) NOEXCEPT;  
579 -CONSTCD11 year_month operator+(const year_month& ym, const years& dy) NOEXCEPT;  
580 -CONSTCD11 year_month operator+(const years& dy, const year_month& ym) NOEXCEPT;  
581 -CONSTCD11 year_month operator-(const year_month& ym, const years& dy) NOEXCEPT;  
582 -  
583 -template<class CharT, class Traits>  
584 -std::basic_ostream<CharT, Traits>&  
585 -operator<<(std::basic_ostream<CharT, Traits>& os, const year_month& ym);  
586 -  
587 -// month_day  
588 -  
589 -class month_day  
590 -{  
591 - date::month m_;  
592 - date::day d_;  
593 -  
594 -public:  
595 - month_day() = default;  
596 - CONSTCD11 month_day(const date::month& m, const date::day& d) NOEXCEPT;  
597 -  
598 - CONSTCD11 date::month month() const NOEXCEPT;  
599 - CONSTCD11 date::day day() const NOEXCEPT;  
600 -  
601 - CONSTCD14 bool ok() const NOEXCEPT;  
602 -};  
603 -  
604 -CONSTCD11 bool operator==(const month_day& x, const month_day& y) NOEXCEPT;  
605 -CONSTCD11 bool operator!=(const month_day& x, const month_day& y) NOEXCEPT;  
606 -CONSTCD11 bool operator< (const month_day& x, const month_day& y) NOEXCEPT;  
607 -CONSTCD11 bool operator> (const month_day& x, const month_day& y) NOEXCEPT;  
608 -CONSTCD11 bool operator<=(const month_day& x, const month_day& y) NOEXCEPT;  
609 -CONSTCD11 bool operator>=(const month_day& x, const month_day& y) NOEXCEPT;  
610 -  
611 -template<class CharT, class Traits>  
612 -std::basic_ostream<CharT, Traits>&  
613 -operator<<(std::basic_ostream<CharT, Traits>& os, const month_day& md);  
614 -  
615 -// month_day_last  
616 -  
617 -class month_day_last  
618 -{  
619 - date::month m_;  
620 -  
621 -public:  
622 - CONSTCD11 explicit month_day_last(const date::month& m) NOEXCEPT;  
623 -  
624 - CONSTCD11 date::month month() const NOEXCEPT;  
625 - CONSTCD11 bool ok() const NOEXCEPT;  
626 -};  
627 -  
628 -CONSTCD11 bool operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT;  
629 -CONSTCD11 bool operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT;  
630 -CONSTCD11 bool operator< (const month_day_last& x, const month_day_last& y) NOEXCEPT;  
631 -CONSTCD11 bool operator> (const month_day_last& x, const month_day_last& y) NOEXCEPT;  
632 -CONSTCD11 bool operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT;  
633 -CONSTCD11 bool operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT;  
634 -  
635 -template<class CharT, class Traits>  
636 -std::basic_ostream<CharT, Traits>&  
637 -operator<<(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl);  
638 -  
639 -// month_weekday  
640 -  
641 -class month_weekday  
642 -{  
643 - date::month m_;  
644 - date::weekday_indexed wdi_;  
645 -public:  
646 - CONSTCD11 month_weekday(const date::month& m,  
647 - const date::weekday_indexed& wdi) NOEXCEPT;  
648 -  
649 - CONSTCD11 date::month month() const NOEXCEPT;  
650 - CONSTCD11 date::weekday_indexed weekday_indexed() const NOEXCEPT;  
651 -  
652 - CONSTCD11 bool ok() const NOEXCEPT;  
653 -};  
654 -  
655 -CONSTCD11 bool operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT;  
656 -CONSTCD11 bool operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT;  
657 -  
658 -template<class CharT, class Traits>  
659 -std::basic_ostream<CharT, Traits>&  
660 -operator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd);  
661 -  
662 -// month_weekday_last  
663 -  
664 -class month_weekday_last  
665 -{  
666 - date::month m_;  
667 - date::weekday_last wdl_;  
668 -  
669 -public:  
670 - CONSTCD11 month_weekday_last(const date::month& m,  
671 - const date::weekday_last& wd) NOEXCEPT;  
672 -  
673 - CONSTCD11 date::month month() const NOEXCEPT;  
674 - CONSTCD11 date::weekday_last weekday_last() const NOEXCEPT;  
675 -  
676 - CONSTCD11 bool ok() const NOEXCEPT;  
677 -};  
678 -  
679 -CONSTCD11  
680 - bool operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT;  
681 -CONSTCD11  
682 - bool operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT;  
683 -  
684 -template<class CharT, class Traits>  
685 -std::basic_ostream<CharT, Traits>&  
686 -operator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl);  
687 -  
688 -// class year_month_day  
689 -  
690 -class year_month_day  
691 -{  
692 - date::year y_;  
693 - date::month m_;  
694 - date::day d_;  
695 -  
696 -public:  
697 - year_month_day() = default;  
698 - CONSTCD11 year_month_day(const date::year& y, const date::month& m,  
699 - const date::day& d) NOEXCEPT;  
700 - CONSTCD14 year_month_day(const year_month_day_last& ymdl) NOEXCEPT;  
701 -  
702 - CONSTCD14 year_month_day(sys_days dp) NOEXCEPT;  
703 - CONSTCD14 explicit year_month_day(local_days dp) NOEXCEPT;  
704 -  
705 - template<class = detail::unspecified_month_disambiguator>  
706 - CONSTCD14 year_month_day& operator+=(const months& m) NOEXCEPT;  
707 - template<class = detail::unspecified_month_disambiguator>  
708 - CONSTCD14 year_month_day& operator-=(const months& m) NOEXCEPT;  
709 - CONSTCD14 year_month_day& operator+=(const years& y) NOEXCEPT;  
710 - CONSTCD14 year_month_day& operator-=(const years& y) NOEXCEPT;  
711 -  
712 - CONSTCD11 date::year year() const NOEXCEPT;  
713 - CONSTCD11 date::month month() const NOEXCEPT;  
714 - CONSTCD11 date::day day() const NOEXCEPT;  
715 -  
716 - CONSTCD14 operator sys_days() const NOEXCEPT;  
717 - CONSTCD14 explicit operator local_days() const NOEXCEPT;  
718 - CONSTCD14 bool ok() const NOEXCEPT;  
719 -  
720 -private:  
721 - static CONSTCD14 year_month_day from_days(days dp) NOEXCEPT;  
722 - CONSTCD14 days to_days() const NOEXCEPT;  
723 -};  
724 -  
725 -CONSTCD11 bool operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT;  
726 -CONSTCD11 bool operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT;  
727 -CONSTCD11 bool operator< (const year_month_day& x, const year_month_day& y) NOEXCEPT;  
728 -CONSTCD11 bool operator> (const year_month_day& x, const year_month_day& y) NOEXCEPT;  
729 -CONSTCD11 bool operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT;  
730 -CONSTCD11 bool operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT;  
731 -  
732 -template<class = detail::unspecified_month_disambiguator>  
733 -CONSTCD14 year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT;  
734 -template<class = detail::unspecified_month_disambiguator>  
735 -CONSTCD14 year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT;  
736 -template<class = detail::unspecified_month_disambiguator>  
737 -CONSTCD14 year_month_day operator-(const year_month_day& ymd, const months& dm) NOEXCEPT;  
738 -CONSTCD11 year_month_day operator+(const year_month_day& ymd, const years& dy) NOEXCEPT;  
739 -CONSTCD11 year_month_day operator+(const years& dy, const year_month_day& ymd) NOEXCEPT;  
740 -CONSTCD11 year_month_day operator-(const year_month_day& ymd, const years& dy) NOEXCEPT;  
741 -  
742 -template<class CharT, class Traits>  
743 -std::basic_ostream<CharT, Traits>&  
744 -operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd);  
745 -  
746 -// year_month_day_last  
747 -  
748 -class year_month_day_last  
749 -{  
750 - date::year y_;  
751 - date::month_day_last mdl_;  
752 -  
753 -public:  
754 - CONSTCD11 year_month_day_last(const date::year& y,  
755 - const date::month_day_last& mdl) NOEXCEPT;  
756 -  
757 - template<class = detail::unspecified_month_disambiguator>  
758 - CONSTCD14 year_month_day_last& operator+=(const months& m) NOEXCEPT;  
759 - template<class = detail::unspecified_month_disambiguator>  
760 - CONSTCD14 year_month_day_last& operator-=(const months& m) NOEXCEPT;  
761 - CONSTCD14 year_month_day_last& operator+=(const years& y) NOEXCEPT;  
762 - CONSTCD14 year_month_day_last& operator-=(const years& y) NOEXCEPT;  
763 -  
764 - CONSTCD11 date::year year() const NOEXCEPT;  
765 - CONSTCD11 date::month month() const NOEXCEPT;  
766 - CONSTCD11 date::month_day_last month_day_last() const NOEXCEPT;  
767 - CONSTCD14 date::day day() const NOEXCEPT;  
768 -  
769 - CONSTCD14 operator sys_days() const NOEXCEPT;  
770 - CONSTCD14 explicit operator local_days() const NOEXCEPT;  
771 - CONSTCD11 bool ok() const NOEXCEPT;  
772 -};  
773 -  
774 -CONSTCD11  
775 - bool operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;  
776 -CONSTCD11  
777 - bool operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;  
778 -CONSTCD11  
779 - bool operator< (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;  
780 -CONSTCD11  
781 - bool operator> (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;  
782 -CONSTCD11  
783 - bool operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;  
784 -CONSTCD11  
785 - bool operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;  
786 -  
787 -template<class = detail::unspecified_month_disambiguator>  
788 -CONSTCD14  
789 -year_month_day_last  
790 -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT;  
791 -  
792 -template<class = detail::unspecified_month_disambiguator>  
793 -CONSTCD14  
794 -year_month_day_last  
795 -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT;  
796 -  
797 -CONSTCD11  
798 -year_month_day_last  
799 -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT;  
800 -  
801 -CONSTCD11  
802 -year_month_day_last  
803 -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT;  
804 -  
805 -template<class = detail::unspecified_month_disambiguator>  
806 -CONSTCD14  
807 -year_month_day_last  
808 -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT;  
809 -  
810 -CONSTCD11  
811 -year_month_day_last  
812 -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT;  
813 -  
814 -template<class CharT, class Traits>  
815 -std::basic_ostream<CharT, Traits>&  
816 -operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl);  
817 -  
818 -// year_month_weekday  
819 -  
820 -class year_month_weekday  
821 -{  
822 - date::year y_;  
823 - date::month m_;  
824 - date::weekday_indexed wdi_;  
825 -  
826 -public:  
827 - year_month_weekday() = default;  
828 - CONSTCD11 year_month_weekday(const date::year& y, const date::month& m,  
829 - const date::weekday_indexed& wdi) NOEXCEPT;  
830 - CONSTCD14 year_month_weekday(const sys_days& dp) NOEXCEPT;  
831 - CONSTCD14 explicit year_month_weekday(const local_days& dp) NOEXCEPT;  
832 -  
833 - template<class = detail::unspecified_month_disambiguator>  
834 - CONSTCD14 year_month_weekday& operator+=(const months& m) NOEXCEPT;  
835 - template<class = detail::unspecified_month_disambiguator>  
836 - CONSTCD14 year_month_weekday& operator-=(const months& m) NOEXCEPT;  
837 - CONSTCD14 year_month_weekday& operator+=(const years& y) NOEXCEPT;  
838 - CONSTCD14 year_month_weekday& operator-=(const years& y) NOEXCEPT;  
839 -  
840 - CONSTCD11 date::year year() const NOEXCEPT;  
841 - CONSTCD11 date::month month() const NOEXCEPT;  
842 - CONSTCD11 date::weekday weekday() const NOEXCEPT;  
843 - CONSTCD11 unsigned index() const NOEXCEPT;  
844 - CONSTCD11 date::weekday_indexed weekday_indexed() const NOEXCEPT;  
845 -  
846 - CONSTCD14 operator sys_days() const NOEXCEPT;  
847 - CONSTCD14 explicit operator local_days() const NOEXCEPT;  
848 - CONSTCD14 bool ok() const NOEXCEPT;  
849 -  
850 -private:  
851 - static CONSTCD14 year_month_weekday from_days(days dp) NOEXCEPT;  
852 - CONSTCD14 days to_days() const NOEXCEPT;  
853 -};  
854 -  
855 -CONSTCD11  
856 - bool operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT;  
857 -CONSTCD11  
858 - bool operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT;  
859 -  
860 -template<class = detail::unspecified_month_disambiguator>  
861 -CONSTCD14  
862 -year_month_weekday  
863 -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT;  
864 -  
865 -template<class = detail::unspecified_month_disambiguator>  
866 -CONSTCD14  
867 -year_month_weekday  
868 -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT;  
869 -  
870 -CONSTCD11  
871 -year_month_weekday  
872 -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT;  
873 -  
874 -CONSTCD11  
875 -year_month_weekday  
876 -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT;  
877 -  
878 -template<class = detail::unspecified_month_disambiguator>  
879 -CONSTCD14  
880 -year_month_weekday  
881 -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT;  
882 -  
883 -CONSTCD11  
884 -year_month_weekday  
885 -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT;  
886 -  
887 -template<class CharT, class Traits>  
888 -std::basic_ostream<CharT, Traits>&  
889 -operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday& ymwdi);  
890 -  
891 -// year_month_weekday_last  
892 -  
893 -class year_month_weekday_last  
894 -{  
895 - date::year y_;  
896 - date::month m_;  
897 - date::weekday_last wdl_;  
898 -  
899 -public:  
900 - CONSTCD11 year_month_weekday_last(const date::year& y, const date::month& m,  
901 - const date::weekday_last& wdl) NOEXCEPT;  
902 -  
903 - template<class = detail::unspecified_month_disambiguator>  
904 - CONSTCD14 year_month_weekday_last& operator+=(const months& m) NOEXCEPT;  
905 - template<class = detail::unspecified_month_disambiguator>  
906 - CONSTCD14 year_month_weekday_last& operator-=(const months& m) NOEXCEPT;  
907 - CONSTCD14 year_month_weekday_last& operator+=(const years& y) NOEXCEPT;  
908 - CONSTCD14 year_month_weekday_last& operator-=(const years& y) NOEXCEPT;  
909 -  
910 - CONSTCD11 date::year year() const NOEXCEPT;  
911 - CONSTCD11 date::month month() const NOEXCEPT;  
912 - CONSTCD11 date::weekday weekday() const NOEXCEPT;  
913 - CONSTCD11 date::weekday_last weekday_last() const NOEXCEPT;  
914 -  
915 - CONSTCD14 operator sys_days() const NOEXCEPT;  
916 - CONSTCD14 explicit operator local_days() const NOEXCEPT;  
917 - CONSTCD11 bool ok() const NOEXCEPT;  
918 -  
919 -private:  
920 - CONSTCD14 days to_days() const NOEXCEPT;  
921 -};  
922 -  
923 -CONSTCD11  
924 -bool  
925 -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT;  
926 -  
927 -CONSTCD11  
928 -bool  
929 -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT;  
930 -  
931 -template<class = detail::unspecified_month_disambiguator>  
932 -CONSTCD14  
933 -year_month_weekday_last  
934 -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT;  
935 -  
936 -template<class = detail::unspecified_month_disambiguator>  
937 -CONSTCD14  
938 -year_month_weekday_last  
939 -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT;  
940 -  
941 -CONSTCD11  
942 -year_month_weekday_last  
943 -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT;  
944 -  
945 -CONSTCD11  
946 -year_month_weekday_last  
947 -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT;  
948 -  
949 -template<class = detail::unspecified_month_disambiguator>  
950 -CONSTCD14  
951 -year_month_weekday_last  
952 -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT;  
953 -  
954 -CONSTCD11  
955 -year_month_weekday_last  
956 -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT;  
957 -  
958 -template<class CharT, class Traits>  
959 -std::basic_ostream<CharT, Traits>&  
960 -operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday_last& ymwdl);  
961 -  
962 -#if !defined(_MSC_VER) || (_MSC_VER >= 1900)  
963 -inline namespace literals  
964 -{  
965 -  
966 -CONSTCD11 date::day operator "" _d(unsigned long long d) NOEXCEPT;  
967 -CONSTCD11 date::year operator "" _y(unsigned long long y) NOEXCEPT;  
968 -  
969 -} // inline namespace literals  
970 -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900)  
971 -  
972 -// CONSTDATA date::month January{1};  
973 -// CONSTDATA date::month February{2};  
974 -// CONSTDATA date::month March{3};  
975 -// CONSTDATA date::month April{4};  
976 -// CONSTDATA date::month May{5};  
977 -// CONSTDATA date::month June{6};  
978 -// CONSTDATA date::month July{7};  
979 -// CONSTDATA date::month August{8};  
980 -// CONSTDATA date::month September{9};  
981 -// CONSTDATA date::month October{10};  
982 -// CONSTDATA date::month November{11};  
983 -// CONSTDATA date::month December{12};  
984 -//  
985 -// CONSTDATA date::weekday Sunday{0u};  
986 -// CONSTDATA date::weekday Monday{1u};  
987 -// CONSTDATA date::weekday Tuesday{2u};  
988 -// CONSTDATA date::weekday Wednesday{3u};  
989 -// CONSTDATA date::weekday Thursday{4u};  
990 -// CONSTDATA date::weekday Friday{5u};  
991 -// CONSTDATA date::weekday Saturday{6u};  
992 -  
993 -#if HAS_VOID_T  
994 -  
995 -template <class T, class = std::void_t<>>  
996 -struct is_clock  
997 - : std::false_type  
998 -{};  
999 -  
1000 -template <class T>  
1001 -struct is_clock<T, std::void_t<decltype(T::now()), typename T::rep, typename T::period,  
1002 - typename T::duration, typename T::time_point,  
1003 - decltype(T::is_steady)>>  
1004 - : std::true_type  
1005 -{};  
1006 -  
1007 -template<class T> inline constexpr bool is_clock_v = is_clock<T>::value;  
1008 -  
1009 -#endif // HAS_VOID_T  
1010 -  
1011 -//----------------+  
1012 -// Implementation |  
1013 -//----------------+  
1014 -  
1015 -// utilities  
1016 -namespace detail {  
1017 -  
1018 -template<class CharT, class Traits = std::char_traits<CharT>>  
1019 -class save_istream  
1020 -{  
1021 -protected:  
1022 - std::basic_ios<CharT, Traits>& is_;  
1023 - CharT fill_;  
1024 - std::ios::fmtflags flags_;  
1025 - std::streamsize precision_;  
1026 - std::streamsize width_;  
1027 - std::basic_ostream<CharT, Traits>* tie_;  
1028 - std::locale loc_;  
1029 -  
1030 -public:  
1031 - ~save_istream()  
1032 - {  
1033 - is_.fill(fill_);  
1034 - is_.flags(flags_);  
1035 - is_.precision(precision_);  
1036 - is_.width(width_);  
1037 - is_.imbue(loc_);  
1038 - is_.tie(tie_);  
1039 - }  
1040 -  
1041 - save_istream(const save_istream&) = delete;  
1042 - save_istream& operator=(const save_istream&) = delete;  
1043 -  
1044 - explicit save_istream(std::basic_ios<CharT, Traits>& is)  
1045 - : is_(is)  
1046 - , fill_(is.fill())  
1047 - , flags_(is.flags())  
1048 - , precision_(is.precision())  
1049 - , width_(is.width(0))  
1050 - , tie_(is.tie(nullptr))  
1051 - , loc_(is.getloc())  
1052 - {  
1053 - if (tie_ != nullptr)  
1054 - tie_->flush();  
1055 - }  
1056 -};  
1057 -  
1058 -template<class CharT, class Traits = std::char_traits<CharT>>  
1059 -class save_ostream  
1060 - : private save_istream<CharT, Traits>  
1061 -{  
1062 -public:  
1063 - ~save_ostream()  
1064 - {  
1065 - if ((this->flags_ & std::ios::unitbuf) &&  
1066 -#if HAS_UNCAUGHT_EXCEPTIONS  
1067 - std::uncaught_exceptions() == 0 &&  
1068 -#else  
1069 - !std::uncaught_exception() &&  
1070 -#endif  
1071 - this->is_.good())  
1072 - this->is_.rdbuf()->pubsync();  
1073 - }  
1074 -  
1075 - save_ostream(const save_ostream&) = delete;  
1076 - save_ostream& operator=(const save_ostream&) = delete;  
1077 -  
1078 - explicit save_ostream(std::basic_ios<CharT, Traits>& os)  
1079 - : save_istream<CharT, Traits>(os)  
1080 - {  
1081 - }  
1082 -};  
1083 -  
1084 -template <class T>  
1085 -struct choose_trunc_type  
1086 -{  
1087 - static const int digits = std::numeric_limits<T>::digits;  
1088 - using type = typename std::conditional  
1089 - <  
1090 - digits < 32,  
1091 - std::int32_t,  
1092 - typename std::conditional  
1093 - <  
1094 - digits < 64,  
1095 - std::int64_t,  
1096 -#ifdef __SIZEOF_INT128__  
1097 - __int128  
1098 -#else  
1099 - std::int64_t  
1100 -#endif  
1101 - >::type  
1102 - >::type;  
1103 -};  
1104 -  
1105 -template <class T>  
1106 -CONSTCD11  
1107 -inline  
1108 -typename std::enable_if  
1109 -<  
1110 - !std::chrono::treat_as_floating_point<T>::value,  
1111 - T  
1112 ->::type  
1113 -trunc(T t) NOEXCEPT  
1114 -{  
1115 - return t;  
1116 -}  
1117 -  
1118 -template <class T>  
1119 -CONSTCD14  
1120 -inline  
1121 -typename std::enable_if  
1122 -<  
1123 - std::chrono::treat_as_floating_point<T>::value,  
1124 - T  
1125 ->::type  
1126 -trunc(T t) NOEXCEPT  
1127 -{  
1128 - using std::numeric_limits;  
1129 - using I = typename choose_trunc_type<T>::type;  
1130 - CONSTDATA auto digits = numeric_limits<T>::digits;  
1131 - static_assert(digits < numeric_limits<I>::digits, "");  
1132 - CONSTDATA auto max = I{1} << (digits-1);  
1133 - CONSTDATA auto min = -max;  
1134 - const auto negative = t < T{0};  
1135 - if (min <= t && t <= max && t != 0 && t == t)  
1136 - {  
1137 - t = static_cast<T>(static_cast<I>(t));  
1138 - if (t == 0 && negative)  
1139 - t = -t;  
1140 - }  
1141 - return t;  
1142 -}  
1143 -  
1144 -template <std::intmax_t Xp, std::intmax_t Yp>  
1145 -struct static_gcd  
1146 -{  
1147 - static const std::intmax_t value = static_gcd<Yp, Xp % Yp>::value;  
1148 -};  
1149 -  
1150 -template <std::intmax_t Xp>  
1151 -struct static_gcd<Xp, 0>  
1152 -{  
1153 - static const std::intmax_t value = Xp;  
1154 -};  
1155 -  
1156 -template <>  
1157 -struct static_gcd<0, 0>  
1158 -{  
1159 - static const std::intmax_t value = 1;  
1160 -};  
1161 -  
1162 -template <class R1, class R2>  
1163 -struct no_overflow  
1164 -{  
1165 -private:  
1166 - static const std::intmax_t gcd_n1_n2 = static_gcd<R1::num, R2::num>::value;  
1167 - static const std::intmax_t gcd_d1_d2 = static_gcd<R1::den, R2::den>::value;  
1168 - static const std::intmax_t n1 = R1::num / gcd_n1_n2;  
1169 - static const std::intmax_t d1 = R1::den / gcd_d1_d2;  
1170 - static const std::intmax_t n2 = R2::num / gcd_n1_n2;  
1171 - static const std::intmax_t d2 = R2::den / gcd_d1_d2;  
1172 -#ifdef __cpp_constexpr  
1173 - static const std::intmax_t max = std::numeric_limits<std::intmax_t>::max();  
1174 -#else  
1175 - static const std::intmax_t max = LLONG_MAX;  
1176 -#endif  
1177 -  
1178 - template <std::intmax_t Xp, std::intmax_t Yp, bool overflow>  
1179 - struct mul // overflow == false  
1180 - {  
1181 - static const std::intmax_t value = Xp * Yp;  
1182 - };  
1183 -  
1184 - template <std::intmax_t Xp, std::intmax_t Yp>  
1185 - struct mul<Xp, Yp, true>  
1186 - {  
1187 - static const std::intmax_t value = 1;  
1188 - };  
1189 -  
1190 -public:  
1191 - static const bool value = (n1 <= max / d2) && (n2 <= max / d1);  
1192 - typedef std::ratio<mul<n1, d2, !value>::value,  
1193 - mul<n2, d1, !value>::value> type;  
1194 -};  
1195 -  
1196 -} // detail  
1197 -  
1198 -// trunc towards zero  
1199 -template <class To, class Rep, class Period>  
1200 -CONSTCD11  
1201 -inline  
1202 -typename std::enable_if  
1203 -<  
1204 - detail::no_overflow<Period, typename To::period>::value,  
1205 - To  
1206 ->::type  
1207 -trunc(const std::chrono::duration<Rep, Period>& d)  
1208 -{  
1209 - return To{detail::trunc(std::chrono::duration_cast<To>(d).count())};  
1210 -}  
1211 -  
1212 -template <class To, class Rep, class Period>  
1213 -CONSTCD11  
1214 -inline  
1215 -typename std::enable_if  
1216 -<  
1217 - !detail::no_overflow<Period, typename To::period>::value,  
1218 - To  
1219 ->::type  
1220 -trunc(const std::chrono::duration<Rep, Period>& d)  
1221 -{  
1222 - using std::chrono::duration_cast;  
1223 - using std::chrono::duration;  
1224 - using rep = typename std::common_type<Rep, typename To::rep>::type;  
1225 - return To{detail::trunc(duration_cast<To>(duration_cast<duration<rep>>(d)).count())};  
1226 -}  
1227 -  
1228 -#ifndef HAS_CHRONO_ROUNDING  
1229 -# if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023918 || (_MSC_FULL_VER >= 190000000 && defined (__clang__)))  
1230 -# define HAS_CHRONO_ROUNDING 1  
1231 -# elif defined(__cpp_lib_chrono) && __cplusplus > 201402 && __cpp_lib_chrono >= 201510  
1232 -# define HAS_CHRONO_ROUNDING 1  
1233 -# elif defined(_LIBCPP_VERSION) && __cplusplus > 201402 && _LIBCPP_VERSION >= 3800  
1234 -# define HAS_CHRONO_ROUNDING 1  
1235 -# else  
1236 -# define HAS_CHRONO_ROUNDING 0  
1237 -# endif  
1238 -#endif // HAS_CHRONO_ROUNDING  
1239 -  
1240 -#if HAS_CHRONO_ROUNDING == 0  
1241 -  
1242 -// round down  
1243 -template <class To, class Rep, class Period>  
1244 -CONSTCD14  
1245 -inline  
1246 -typename std::enable_if  
1247 -<  
1248 - detail::no_overflow<Period, typename To::period>::value,  
1249 - To  
1250 ->::type  
1251 -floor(const std::chrono::duration<Rep, Period>& d)  
1252 -{  
1253 - auto t = trunc<To>(d);  
1254 - if (t > d)  
1255 - return t - To{1};  
1256 - return t;  
1257 -}  
1258 -  
1259 -template <class To, class Rep, class Period>  
1260 -CONSTCD14  
1261 -inline  
1262 -typename std::enable_if  
1263 -<  
1264 - !detail::no_overflow<Period, typename To::period>::value,  
1265 - To  
1266 ->::type  
1267 -floor(const std::chrono::duration<Rep, Period>& d)  
1268 -{  
1269 - using rep = typename std::common_type<Rep, typename To::rep>::type;  
1270 - return floor<To>(floor<std::chrono::duration<rep>>(d));  
1271 -}  
1272 -  
1273 -// round to nearest, to even on tie  
1274 -template <class To, class Rep, class Period>  
1275 -CONSTCD14  
1276 -inline  
1277 -To  
1278 -round(const std::chrono::duration<Rep, Period>& d)  
1279 -{  
1280 - auto t0 = floor<To>(d);  
1281 - auto t1 = t0 + To{1};  
1282 - if (t1 == To{0} && t0 < To{0})  
1283 - t1 = -t1;  
1284 - auto diff0 = d - t0;  
1285 - auto diff1 = t1 - d;  
1286 - if (diff0 == diff1)  
1287 - {  
1288 - if (t0 - trunc<To>(t0/2)*2 == To{0})  
1289 - return t0;  
1290 - return t1;  
1291 - }  
1292 - if (diff0 < diff1)  
1293 - return t0;  
1294 - return t1;  
1295 -}  
1296 -  
1297 -// round up  
1298 -template <class To, class Rep, class Period>  
1299 -CONSTCD14  
1300 -inline  
1301 -To  
1302 -ceil(const std::chrono::duration<Rep, Period>& d)  
1303 -{  
1304 - auto t = trunc<To>(d);  
1305 - if (t < d)  
1306 - return t + To{1};  
1307 - return t;  
1308 -}  
1309 -  
1310 -template <class Rep, class Period,  
1311 - class = typename std::enable_if  
1312 - <  
1313 - std::numeric_limits<Rep>::is_signed  
1314 - >::type>  
1315 -CONSTCD11  
1316 -std::chrono::duration<Rep, Period>  
1317 -abs(std::chrono::duration<Rep, Period> d)  
1318 -{  
1319 - return d >= d.zero() ? d : -d;  
1320 -}  
1321 -  
1322 -// round down  
1323 -template <class To, class Clock, class FromDuration>  
1324 -CONSTCD11  
1325 -inline  
1326 -std::chrono::time_point<Clock, To>  
1327 -floor(const std::chrono::time_point<Clock, FromDuration>& tp)  
1328 -{  
1329 - using std::chrono::time_point;  
1330 - return time_point<Clock, To>{date::floor<To>(tp.time_since_epoch())};  
1331 -}  
1332 -  
1333 -// round to nearest, to even on tie  
1334 -template <class To, class Clock, class FromDuration>  
1335 -CONSTCD11  
1336 -inline  
1337 -std::chrono::time_point<Clock, To>  
1338 -round(const std::chrono::time_point<Clock, FromDuration>& tp)  
1339 -{  
1340 - using std::chrono::time_point;  
1341 - return time_point<Clock, To>{round<To>(tp.time_since_epoch())};  
1342 -}  
1343 -  
1344 -// round up  
1345 -template <class To, class Clock, class FromDuration>  
1346 -CONSTCD11  
1347 -inline  
1348 -std::chrono::time_point<Clock, To>  
1349 -ceil(const std::chrono::time_point<Clock, FromDuration>& tp)  
1350 -{  
1351 - using std::chrono::time_point;  
1352 - return time_point<Clock, To>{ceil<To>(tp.time_since_epoch())};  
1353 -}  
1354 -  
1355 -#else // HAS_CHRONO_ROUNDING == 1  
1356 -  
1357 -using std::chrono::floor;  
1358 -using std::chrono::ceil;  
1359 -using std::chrono::round;  
1360 -using std::chrono::abs;  
1361 -  
1362 -#endif // HAS_CHRONO_ROUNDING  
1363 -  
1364 -namespace detail  
1365 -{  
1366 -  
1367 -template <class To, class Rep, class Period>  
1368 -CONSTCD14  
1369 -inline  
1370 -typename std::enable_if  
1371 -<  
1372 - !std::chrono::treat_as_floating_point<typename To::rep>::value,  
1373 - To  
1374 ->::type  
1375 -round_i(const std::chrono::duration<Rep, Period>& d)  
1376 -{  
1377 - return round<To>(d);  
1378 -}  
1379 -  
1380 -template <class To, class Rep, class Period>  
1381 -CONSTCD14  
1382 -inline  
1383 -typename std::enable_if  
1384 -<  
1385 - std::chrono::treat_as_floating_point<typename To::rep>::value,  
1386 - To  
1387 ->::type  
1388 -round_i(const std::chrono::duration<Rep, Period>& d)  
1389 -{  
1390 - return d;  
1391 -}  
1392 -  
1393 -template <class To, class Clock, class FromDuration>  
1394 -CONSTCD11  
1395 -inline  
1396 -std::chrono::time_point<Clock, To>  
1397 -round_i(const std::chrono::time_point<Clock, FromDuration>& tp)  
1398 -{  
1399 - using std::chrono::time_point;  
1400 - return time_point<Clock, To>{round_i<To>(tp.time_since_epoch())};  
1401 -}  
1402 -  
1403 -} // detail  
1404 -  
1405 -// trunc towards zero  
1406 -template <class To, class Clock, class FromDuration>  
1407 -CONSTCD11  
1408 -inline  
1409 -std::chrono::time_point<Clock, To>  
1410 -trunc(const std::chrono::time_point<Clock, FromDuration>& tp)  
1411 -{  
1412 - using std::chrono::time_point;  
1413 - return time_point<Clock, To>{trunc<To>(tp.time_since_epoch())};  
1414 -}  
1415 -  
1416 -// day  
1417 -  
1418 -CONSTCD11 inline day::day(unsigned d) NOEXCEPT : d_(static_cast<decltype(d_)>(d)) {}  
1419 -CONSTCD14 inline day& day::operator++() NOEXCEPT {++d_; return *this;}  
1420 -CONSTCD14 inline day day::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;}  
1421 -CONSTCD14 inline day& day::operator--() NOEXCEPT {--d_; return *this;}  
1422 -CONSTCD14 inline day day::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;}  
1423 -CONSTCD14 inline day& day::operator+=(const days& d) NOEXCEPT {*this = *this + d; return *this;}  
1424 -CONSTCD14 inline day& day::operator-=(const days& d) NOEXCEPT {*this = *this - d; return *this;}  
1425 -CONSTCD11 inline day::operator unsigned() const NOEXCEPT {return d_;}  
1426 -CONSTCD11 inline bool day::ok() const NOEXCEPT {return 1 <= d_ && d_ <= 31;}  
1427 -  
1428 -CONSTCD11  
1429 -inline  
1430 -bool  
1431 -operator==(const day& x, const day& y) NOEXCEPT  
1432 -{  
1433 - return static_cast<unsigned>(x) == static_cast<unsigned>(y);  
1434 -}  
1435 -  
1436 -CONSTCD11  
1437 -inline  
1438 -bool  
1439 -operator!=(const day& x, const day& y) NOEXCEPT  
1440 -{  
1441 - return !(x == y);  
1442 -}  
1443 -  
1444 -CONSTCD11  
1445 -inline  
1446 -bool  
1447 -operator<(const day& x, const day& y) NOEXCEPT  
1448 -{  
1449 - return static_cast<unsigned>(x) < static_cast<unsigned>(y);  
1450 -}  
1451 -  
1452 -CONSTCD11  
1453 -inline  
1454 -bool  
1455 -operator>(const day& x, const day& y) NOEXCEPT  
1456 -{  
1457 - return y < x;  
1458 -}  
1459 -  
1460 -CONSTCD11  
1461 -inline  
1462 -bool  
1463 -operator<=(const day& x, const day& y) NOEXCEPT  
1464 -{  
1465 - return !(y < x);  
1466 -}  
1467 -  
1468 -CONSTCD11  
1469 -inline  
1470 -bool  
1471 -operator>=(const day& x, const day& y) NOEXCEPT  
1472 -{  
1473 - return !(x < y);  
1474 -}  
1475 -  
1476 -CONSTCD11  
1477 -inline  
1478 -days  
1479 -operator-(const day& x, const day& y) NOEXCEPT  
1480 -{  
1481 - return days{static_cast<days::rep>(static_cast<unsigned>(x)  
1482 - - static_cast<unsigned>(y))};  
1483 -}  
1484 -  
1485 -CONSTCD11  
1486 -inline  
1487 -day  
1488 -operator+(const day& x, const days& y) NOEXCEPT  
1489 -{  
1490 - return day{static_cast<unsigned>(x) + static_cast<unsigned>(y.count())};  
1491 -}  
1492 -  
1493 -CONSTCD11  
1494 -inline  
1495 -day  
1496 -operator+(const days& x, const day& y) NOEXCEPT  
1497 -{  
1498 - return y + x;  
1499 -}  
1500 -  
1501 -CONSTCD11  
1502 -inline  
1503 -day  
1504 -operator-(const day& x, const days& y) NOEXCEPT  
1505 -{  
1506 - return x + -y;  
1507 -}  
1508 -  
1509 -namespace detail  
1510 -{  
1511 -  
1512 -template<class CharT, class Traits>  
1513 -std::basic_ostream<CharT, Traits>&  
1514 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const day& d)  
1515 -{  
1516 - detail::save_ostream<CharT, Traits> _(os);  
1517 - os.fill('0');  
1518 - os.flags(std::ios::dec | std::ios::right);  
1519 - os.width(2);  
1520 - os << static_cast<unsigned>(d);  
1521 - return os;  
1522 -}  
1523 -  
1524 -} // namespace detail  
1525 -  
1526 -template<class CharT, class Traits>  
1527 -inline  
1528 -std::basic_ostream<CharT, Traits>&  
1529 -operator<<(std::basic_ostream<CharT, Traits>& os, const day& d)  
1530 -{  
1531 - detail::low_level_fmt(os, d);  
1532 - if (!d.ok())  
1533 - os << " is not a valid day";  
1534 - return os;  
1535 -}  
1536 -  
1537 -// month  
1538 -  
1539 -CONSTCD11 inline month::month(unsigned m) NOEXCEPT : m_(static_cast<decltype(m_)>(m)) {}  
1540 -CONSTCD14 inline month& month::operator++() NOEXCEPT {*this += months{1}; return *this;}  
1541 -CONSTCD14 inline month month::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;}  
1542 -CONSTCD14 inline month& month::operator--() NOEXCEPT {*this -= months{1}; return *this;}  
1543 -CONSTCD14 inline month month::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;}  
1544 -  
1545 -CONSTCD14  
1546 -inline  
1547 -month&  
1548 -month::operator+=(const months& m) NOEXCEPT  
1549 -{  
1550 - *this = *this + m;  
1551 - return *this;  
1552 -}  
1553 -  
1554 -CONSTCD14  
1555 -inline  
1556 -month&  
1557 -month::operator-=(const months& m) NOEXCEPT  
1558 -{  
1559 - *this = *this - m;  
1560 - return *this;  
1561 -}  
1562 -  
1563 -CONSTCD11 inline month::operator unsigned() const NOEXCEPT {return m_;}  
1564 -CONSTCD11 inline bool month::ok() const NOEXCEPT {return 1 <= m_ && m_ <= 12;}  
1565 -  
1566 -CONSTCD11  
1567 -inline  
1568 -bool  
1569 -operator==(const month& x, const month& y) NOEXCEPT  
1570 -{  
1571 - return static_cast<unsigned>(x) == static_cast<unsigned>(y);  
1572 -}  
1573 -  
1574 -CONSTCD11  
1575 -inline  
1576 -bool  
1577 -operator!=(const month& x, const month& y) NOEXCEPT  
1578 -{  
1579 - return !(x == y);  
1580 -}  
1581 -  
1582 -CONSTCD11  
1583 -inline  
1584 -bool  
1585 -operator<(const month& x, const month& y) NOEXCEPT  
1586 -{  
1587 - return static_cast<unsigned>(x) < static_cast<unsigned>(y);  
1588 -}  
1589 -  
1590 -CONSTCD11  
1591 -inline  
1592 -bool  
1593 -operator>(const month& x, const month& y) NOEXCEPT  
1594 -{  
1595 - return y < x;  
1596 -}  
1597 -  
1598 -CONSTCD11  
1599 -inline  
1600 -bool  
1601 -operator<=(const month& x, const month& y) NOEXCEPT  
1602 -{  
1603 - return !(y < x);  
1604 -}  
1605 -  
1606 -CONSTCD11  
1607 -inline  
1608 -bool  
1609 -operator>=(const month& x, const month& y) NOEXCEPT  
1610 -{  
1611 - return !(x < y);  
1612 -}  
1613 -  
1614 -CONSTCD14  
1615 -inline  
1616 -months  
1617 -operator-(const month& x, const month& y) NOEXCEPT  
1618 -{  
1619 - auto const d = static_cast<unsigned>(x) - static_cast<unsigned>(y);  
1620 - return months(d <= 11 ? d : d + 12);  
1621 -}  
1622 -  
1623 -CONSTCD14  
1624 -inline  
1625 -month  
1626 -operator+(const month& x, const months& y) NOEXCEPT  
1627 -{  
1628 - auto const mu = static_cast<long long>(static_cast<unsigned>(x)) + y.count() - 1;  
1629 - auto const yr = (mu >= 0 ? mu : mu-11) / 12;  
1630 - return month{static_cast<unsigned>(mu - yr * 12 + 1)};  
1631 -}  
1632 -  
1633 -CONSTCD14  
1634 -inline  
1635 -month  
1636 -operator+(const months& x, const month& y) NOEXCEPT  
1637 -{  
1638 - return y + x;  
1639 -}  
1640 -  
1641 -CONSTCD14  
1642 -inline  
1643 -month  
1644 -operator-(const month& x, const months& y) NOEXCEPT  
1645 -{  
1646 - return x + -y;  
1647 -}  
1648 -  
1649 -namespace detail  
1650 -{  
1651 -  
1652 -template<class CharT, class Traits>  
1653 -std::basic_ostream<CharT, Traits>&  
1654 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month& m)  
1655 -{  
1656 - if (m.ok())  
1657 - {  
1658 - CharT fmt[] = {'%', 'b', 0};  
1659 - os << format(os.getloc(), fmt, m);  
1660 - }  
1661 - else  
1662 - os << static_cast<unsigned>(m);  
1663 - return os;  
1664 -}  
1665 -  
1666 -} // namespace detail  
1667 -  
1668 -template<class CharT, class Traits>  
1669 -inline  
1670 -std::basic_ostream<CharT, Traits>&  
1671 -operator<<(std::basic_ostream<CharT, Traits>& os, const month& m)  
1672 -{  
1673 - detail::low_level_fmt(os, m);  
1674 - if (!m.ok())  
1675 - os << " is not a valid month";  
1676 - return os;  
1677 -}  
1678 -  
1679 -// year  
1680 -  
1681 -CONSTCD11 inline year::year(int y) NOEXCEPT : y_(static_cast<decltype(y_)>(y)) {}  
1682 -CONSTCD14 inline year& year::operator++() NOEXCEPT {++y_; return *this;}  
1683 -CONSTCD14 inline year year::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;}  
1684 -CONSTCD14 inline year& year::operator--() NOEXCEPT {--y_; return *this;}  
1685 -CONSTCD14 inline year year::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;}  
1686 -CONSTCD14 inline year& year::operator+=(const years& y) NOEXCEPT {*this = *this + y; return *this;}  
1687 -CONSTCD14 inline year& year::operator-=(const years& y) NOEXCEPT {*this = *this - y; return *this;}  
1688 -CONSTCD11 inline year year::operator-() const NOEXCEPT {return year{-y_};}  
1689 -CONSTCD11 inline year year::operator+() const NOEXCEPT {return *this;}  
1690 -  
1691 -CONSTCD11  
1692 -inline  
1693 -bool  
1694 -year::is_leap() const NOEXCEPT  
1695 -{  
1696 - return y_ % 4 == 0 && (y_ % 100 != 0 || y_ % 400 == 0);  
1697 -}  
1698 -  
1699 -CONSTCD11 inline year::operator int() const NOEXCEPT {return y_;}  
1700 -  
1701 -CONSTCD11  
1702 -inline  
1703 -bool  
1704 -year::ok() const NOEXCEPT  
1705 -{  
1706 - return y_ != std::numeric_limits<short>::min();  
1707 -}  
1708 -  
1709 -CONSTCD11  
1710 -inline  
1711 -bool  
1712 -operator==(const year& x, const year& y) NOEXCEPT  
1713 -{  
1714 - return static_cast<int>(x) == static_cast<int>(y);  
1715 -}  
1716 -  
1717 -CONSTCD11  
1718 -inline  
1719 -bool  
1720 -operator!=(const year& x, const year& y) NOEXCEPT  
1721 -{  
1722 - return !(x == y);  
1723 -}  
1724 -  
1725 -CONSTCD11  
1726 -inline  
1727 -bool  
1728 -operator<(const year& x, const year& y) NOEXCEPT  
1729 -{  
1730 - return static_cast<int>(x) < static_cast<int>(y);  
1731 -}  
1732 -  
1733 -CONSTCD11  
1734 -inline  
1735 -bool  
1736 -operator>(const year& x, const year& y) NOEXCEPT  
1737 -{  
1738 - return y < x;  
1739 -}  
1740 -  
1741 -CONSTCD11  
1742 -inline  
1743 -bool  
1744 -operator<=(const year& x, const year& y) NOEXCEPT  
1745 -{  
1746 - return !(y < x);  
1747 -}  
1748 -  
1749 -CONSTCD11  
1750 -inline  
1751 -bool  
1752 -operator>=(const year& x, const year& y) NOEXCEPT  
1753 -{  
1754 - return !(x < y);  
1755 -}  
1756 -  
1757 -CONSTCD11  
1758 -inline  
1759 -years  
1760 -operator-(const year& x, const year& y) NOEXCEPT  
1761 -{  
1762 - return years{static_cast<int>(x) - static_cast<int>(y)};  
1763 -}  
1764 -  
1765 -CONSTCD11  
1766 -inline  
1767 -year  
1768 -operator+(const year& x, const years& y) NOEXCEPT  
1769 -{  
1770 - return year{static_cast<int>(x) + y.count()};  
1771 -}  
1772 -  
1773 -CONSTCD11  
1774 -inline  
1775 -year  
1776 -operator+(const years& x, const year& y) NOEXCEPT  
1777 -{  
1778 - return y + x;  
1779 -}  
1780 -  
1781 -CONSTCD11  
1782 -inline  
1783 -year  
1784 -operator-(const year& x, const years& y) NOEXCEPT  
1785 -{  
1786 - return year{static_cast<int>(x) - y.count()};  
1787 -}  
1788 -  
1789 -namespace detail  
1790 -{  
1791 -  
1792 -template<class CharT, class Traits>  
1793 -std::basic_ostream<CharT, Traits>&  
1794 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const year& y)  
1795 -{  
1796 - detail::save_ostream<CharT, Traits> _(os);  
1797 - os.fill('0');  
1798 - os.flags(std::ios::dec | std::ios::internal);  
1799 - os.width(4 + (y < year{0}));  
1800 - os.imbue(std::locale::classic());  
1801 - os << static_cast<int>(y);  
1802 - return os;  
1803 -}  
1804 -  
1805 -} // namespace detail  
1806 -  
1807 -template<class CharT, class Traits>  
1808 -inline  
1809 -std::basic_ostream<CharT, Traits>&  
1810 -operator<<(std::basic_ostream<CharT, Traits>& os, const year& y)  
1811 -{  
1812 - detail::low_level_fmt(os, y);  
1813 - if (!y.ok())  
1814 - os << " is not a valid year";  
1815 - return os;  
1816 -}  
1817 -  
1818 -// weekday  
1819 -  
1820 -CONSTCD14  
1821 -inline  
1822 -unsigned char  
1823 -weekday::weekday_from_days(int z) NOEXCEPT  
1824 -{  
1825 - auto u = static_cast<unsigned>(z);  
1826 - return static_cast<unsigned char>(z >= -4 ? (u+4) % 7 : u % 7);  
1827 -}  
1828 -  
1829 -CONSTCD11  
1830 -inline  
1831 -weekday::weekday(unsigned wd) NOEXCEPT  
1832 - : wd_(static_cast<decltype(wd_)>(wd != 7 ? wd : 0))  
1833 - {}  
1834 -  
1835 -CONSTCD14  
1836 -inline  
1837 -weekday::weekday(const sys_days& dp) NOEXCEPT  
1838 - : wd_(weekday_from_days(dp.time_since_epoch().count()))  
1839 - {}  
1840 -  
1841 -CONSTCD14  
1842 -inline  
1843 -weekday::weekday(const local_days& dp) NOEXCEPT  
1844 - : wd_(weekday_from_days(dp.time_since_epoch().count()))  
1845 - {}  
1846 -  
1847 -CONSTCD14 inline weekday& weekday::operator++() NOEXCEPT {*this += days{1}; return *this;}  
1848 -CONSTCD14 inline weekday weekday::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;}  
1849 -CONSTCD14 inline weekday& weekday::operator--() NOEXCEPT {*this -= days{1}; return *this;}  
1850 -CONSTCD14 inline weekday weekday::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;}  
1851 -  
1852 -CONSTCD14  
1853 -inline  
1854 -weekday&  
1855 -weekday::operator+=(const days& d) NOEXCEPT  
1856 -{  
1857 - *this = *this + d;  
1858 - return *this;  
1859 -}  
1860 -  
1861 -CONSTCD14  
1862 -inline  
1863 -weekday&  
1864 -weekday::operator-=(const days& d) NOEXCEPT  
1865 -{  
1866 - *this = *this - d;  
1867 - return *this;  
1868 -}  
1869 -  
1870 -CONSTCD11 inline bool weekday::ok() const NOEXCEPT {return wd_ <= 6;}  
1871 -  
1872 -CONSTCD11  
1873 -inline  
1874 -unsigned weekday::c_encoding() const NOEXCEPT  
1875 -{  
1876 - return unsigned{wd_};  
1877 -}  
1878 -  
1879 -CONSTCD11  
1880 -inline  
1881 -unsigned weekday::iso_encoding() const NOEXCEPT  
1882 -{  
1883 - return unsigned{((wd_ == 0u) ? 7u : wd_)};  
1884 -}  
1885 -  
1886 -CONSTCD11  
1887 -inline  
1888 -bool  
1889 -operator==(const weekday& x, const weekday& y) NOEXCEPT  
1890 -{  
1891 - return x.wd_ == y.wd_;  
1892 -}  
1893 -  
1894 -CONSTCD11  
1895 -inline  
1896 -bool  
1897 -operator!=(const weekday& x, const weekday& y) NOEXCEPT  
1898 -{  
1899 - return !(x == y);  
1900 -}  
1901 -  
1902 -CONSTCD14  
1903 -inline  
1904 -days  
1905 -operator-(const weekday& x, const weekday& y) NOEXCEPT  
1906 -{  
1907 - auto const wdu = x.wd_ - y.wd_;  
1908 - auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7;  
1909 - return days{wdu - wk * 7};  
1910 -}  
1911 -  
1912 -CONSTCD14  
1913 -inline  
1914 -weekday  
1915 -operator+(const weekday& x, const days& y) NOEXCEPT  
1916 -{  
1917 - auto const wdu = static_cast<long long>(static_cast<unsigned>(x.wd_)) + y.count();  
1918 - auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7;  
1919 - return weekday{static_cast<unsigned>(wdu - wk * 7)};  
1920 -}  
1921 -  
1922 -CONSTCD14  
1923 -inline  
1924 -weekday  
1925 -operator+(const days& x, const weekday& y) NOEXCEPT  
1926 -{  
1927 - return y + x;  
1928 -}  
1929 -  
1930 -CONSTCD14  
1931 -inline  
1932 -weekday  
1933 -operator-(const weekday& x, const days& y) NOEXCEPT  
1934 -{  
1935 - return x + -y;  
1936 -}  
1937 -  
1938 -namespace detail  
1939 -{  
1940 -  
1941 -template<class CharT, class Traits>  
1942 -std::basic_ostream<CharT, Traits>&  
1943 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday& wd)  
1944 -{  
1945 - if (wd.ok())  
1946 - {  
1947 - CharT fmt[] = {'%', 'a', 0};  
1948 - os << format(fmt, wd);  
1949 - }  
1950 - else  
1951 - os << wd.c_encoding();  
1952 - return os;  
1953 -}  
1954 -  
1955 -} // namespace detail  
1956 -  
1957 -template<class CharT, class Traits>  
1958 -inline  
1959 -std::basic_ostream<CharT, Traits>&  
1960 -operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd)  
1961 -{  
1962 - detail::low_level_fmt(os, wd);  
1963 - if (!wd.ok())  
1964 - os << " is not a valid weekday";  
1965 - return os;  
1966 -}  
1967 -  
1968 -#if !defined(_MSC_VER) || (_MSC_VER >= 1900)  
1969 -inline namespace literals  
1970 -{  
1971 -  
1972 -CONSTCD11  
1973 -inline  
1974 -date::day  
1975 -operator "" _d(unsigned long long d) NOEXCEPT  
1976 -{  
1977 - return date::day{static_cast<unsigned>(d)};  
1978 -}  
1979 -  
1980 -CONSTCD11  
1981 -inline  
1982 -date::year  
1983 -operator "" _y(unsigned long long y) NOEXCEPT  
1984 -{  
1985 - return date::year(static_cast<int>(y));  
1986 -}  
1987 -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900)  
1988 -  
1989 -CONSTDATA date::last_spec last{};  
1990 -  
1991 -CONSTDATA date::month jan{1};  
1992 -CONSTDATA date::month feb{2};  
1993 -CONSTDATA date::month mar{3};  
1994 -CONSTDATA date::month apr{4};  
1995 -CONSTDATA date::month may{5};  
1996 -CONSTDATA date::month jun{6};  
1997 -CONSTDATA date::month jul{7};  
1998 -CONSTDATA date::month aug{8};  
1999 -CONSTDATA date::month sep{9};  
2000 -CONSTDATA date::month oct{10};  
2001 -CONSTDATA date::month nov{11};  
2002 -CONSTDATA date::month dec{12};  
2003 -  
2004 -CONSTDATA date::weekday sun{0u};  
2005 -CONSTDATA date::weekday mon{1u};  
2006 -CONSTDATA date::weekday tue{2u};  
2007 -CONSTDATA date::weekday wed{3u};  
2008 -CONSTDATA date::weekday thu{4u};  
2009 -CONSTDATA date::weekday fri{5u};  
2010 -CONSTDATA date::weekday sat{6u};  
2011 -  
2012 -#if !defined(_MSC_VER) || (_MSC_VER >= 1900)  
2013 -} // inline namespace literals  
2014 -#endif  
2015 -  
2016 -CONSTDATA date::month January{1};  
2017 -CONSTDATA date::month February{2};  
2018 -CONSTDATA date::month March{3};  
2019 -CONSTDATA date::month April{4};  
2020 -CONSTDATA date::month May{5};  
2021 -CONSTDATA date::month June{6};  
2022 -CONSTDATA date::month July{7};  
2023 -CONSTDATA date::month August{8};  
2024 -CONSTDATA date::month September{9};  
2025 -CONSTDATA date::month October{10};  
2026 -CONSTDATA date::month November{11};  
2027 -CONSTDATA date::month December{12};  
2028 -  
2029 -CONSTDATA date::weekday Monday{1};  
2030 -CONSTDATA date::weekday Tuesday{2};  
2031 -CONSTDATA date::weekday Wednesday{3};  
2032 -CONSTDATA date::weekday Thursday{4};  
2033 -CONSTDATA date::weekday Friday{5};  
2034 -CONSTDATA date::weekday Saturday{6};  
2035 -CONSTDATA date::weekday Sunday{7};  
2036 -  
2037 -// weekday_indexed  
2038 -  
2039 -CONSTCD11  
2040 -inline  
2041 -weekday  
2042 -weekday_indexed::weekday() const NOEXCEPT  
2043 -{  
2044 - return date::weekday{static_cast<unsigned>(wd_)};  
2045 -}  
2046 -  
2047 -CONSTCD11 inline unsigned weekday_indexed::index() const NOEXCEPT {return index_;}  
2048 -  
2049 -CONSTCD11  
2050 -inline  
2051 -bool  
2052 -weekday_indexed::ok() const NOEXCEPT  
2053 -{  
2054 - return weekday().ok() && 1 <= index_ && index_ <= 5;  
2055 -}  
2056 -  
2057 -#ifdef __GNUC__  
2058 -# pragma GCC diagnostic push  
2059 -# pragma GCC diagnostic ignored "-Wconversion"  
2060 -#endif // __GNUC__  
2061 -  
2062 -CONSTCD11  
2063 -inline  
2064 -weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT  
2065 - : wd_(static_cast<decltype(wd_)>(static_cast<unsigned>(wd.wd_)))  
2066 - , index_(static_cast<decltype(index_)>(index))  
2067 - {}  
2068 -  
2069 -#ifdef __GNUC__  
2070 -# pragma GCC diagnostic pop  
2071 -#endif // __GNUC__  
2072 -  
2073 -namespace detail  
2074 -{  
2075 -  
2076 -template<class CharT, class Traits>  
2077 -std::basic_ostream<CharT, Traits>&  
2078 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi)  
2079 -{  
2080 - return low_level_fmt(os, wdi.weekday()) << '[' << wdi.index() << ']';  
2081 -}  
2082 -  
2083 -} // namespace detail  
2084 -  
2085 -template<class CharT, class Traits>  
2086 -inline  
2087 -std::basic_ostream<CharT, Traits>&  
2088 -operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi)  
2089 -{  
2090 - detail::low_level_fmt(os, wdi);  
2091 - if (!wdi.ok())  
2092 - os << " is not a valid weekday_indexed";  
2093 - return os;  
2094 -}  
2095 -  
2096 -CONSTCD11  
2097 -inline  
2098 -weekday_indexed  
2099 -weekday::operator[](unsigned index) const NOEXCEPT  
2100 -{  
2101 - return {*this, index};  
2102 -}  
2103 -  
2104 -CONSTCD11  
2105 -inline  
2106 -bool  
2107 -operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT  
2108 -{  
2109 - return x.weekday() == y.weekday() && x.index() == y.index();  
2110 -}  
2111 -  
2112 -CONSTCD11  
2113 -inline  
2114 -bool  
2115 -operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT  
2116 -{  
2117 - return !(x == y);  
2118 -}  
2119 -  
2120 -// weekday_last  
2121 -  
2122 -CONSTCD11 inline date::weekday weekday_last::weekday() const NOEXCEPT {return wd_;}  
2123 -CONSTCD11 inline bool weekday_last::ok() const NOEXCEPT {return wd_.ok();}  
2124 -CONSTCD11 inline weekday_last::weekday_last(const date::weekday& wd) NOEXCEPT : wd_(wd) {}  
2125 -  
2126 -CONSTCD11  
2127 -inline  
2128 -bool  
2129 -operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT  
2130 -{  
2131 - return x.weekday() == y.weekday();  
2132 -}  
2133 -  
2134 -CONSTCD11  
2135 -inline  
2136 -bool  
2137 -operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT  
2138 -{  
2139 - return !(x == y);  
2140 -}  
2141 -  
2142 -namespace detail  
2143 -{  
2144 -  
2145 -template<class CharT, class Traits>  
2146 -std::basic_ostream<CharT, Traits>&  
2147 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl)  
2148 -{  
2149 - return low_level_fmt(os, wdl.weekday()) << "[last]";  
2150 -}  
2151 -  
2152 -} // namespace detail  
2153 -  
2154 -template<class CharT, class Traits>  
2155 -inline  
2156 -std::basic_ostream<CharT, Traits>&  
2157 -operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl)  
2158 -{  
2159 - detail::low_level_fmt(os, wdl);  
2160 - if (!wdl.ok())  
2161 - os << " is not a valid weekday_last";  
2162 - return os;  
2163 -}  
2164 -  
2165 -CONSTCD11  
2166 -inline  
2167 -weekday_last  
2168 -weekday::operator[](last_spec) const NOEXCEPT  
2169 -{  
2170 - return weekday_last{*this};  
2171 -}  
2172 -  
2173 -// year_month  
2174 -  
2175 -CONSTCD11  
2176 -inline  
2177 -year_month::year_month(const date::year& y, const date::month& m) NOEXCEPT  
2178 - : y_(y)  
2179 - , m_(m)  
2180 - {}  
2181 -  
2182 -CONSTCD11 inline year year_month::year() const NOEXCEPT {return y_;}  
2183 -CONSTCD11 inline month year_month::month() const NOEXCEPT {return m_;}  
2184 -CONSTCD11 inline bool year_month::ok() const NOEXCEPT {return y_.ok() && m_.ok();}  
2185 -  
2186 -template<class>  
2187 -CONSTCD14  
2188 -inline  
2189 -year_month&  
2190 -year_month::operator+=(const months& dm) NOEXCEPT  
2191 -{  
2192 - *this = *this + dm;  
2193 - return *this;  
2194 -}  
2195 -  
2196 -template<class>  
2197 -CONSTCD14  
2198 -inline  
2199 -year_month&  
2200 -year_month::operator-=(const months& dm) NOEXCEPT  
2201 -{  
2202 - *this = *this - dm;  
2203 - return *this;  
2204 -}  
2205 -  
2206 -CONSTCD14  
2207 -inline  
2208 -year_month&  
2209 -year_month::operator+=(const years& dy) NOEXCEPT  
2210 -{  
2211 - *this = *this + dy;  
2212 - return *this;  
2213 -}  
2214 -  
2215 -CONSTCD14  
2216 -inline  
2217 -year_month&  
2218 -year_month::operator-=(const years& dy) NOEXCEPT  
2219 -{  
2220 - *this = *this - dy;  
2221 - return *this;  
2222 -}  
2223 -  
2224 -CONSTCD11  
2225 -inline  
2226 -bool  
2227 -operator==(const year_month& x, const year_month& y) NOEXCEPT  
2228 -{  
2229 - return x.year() == y.year() && x.month() == y.month();  
2230 -}  
2231 -  
2232 -CONSTCD11  
2233 -inline  
2234 -bool  
2235 -operator!=(const year_month& x, const year_month& y) NOEXCEPT  
2236 -{  
2237 - return !(x == y);  
2238 -}  
2239 -  
2240 -CONSTCD11  
2241 -inline  
2242 -bool  
2243 -operator<(const year_month& x, const year_month& y) NOEXCEPT  
2244 -{  
2245 - return x.year() < y.year() ? true  
2246 - : (x.year() > y.year() ? false  
2247 - : (x.month() < y.month()));  
2248 -}  
2249 -  
2250 -CONSTCD11  
2251 -inline  
2252 -bool  
2253 -operator>(const year_month& x, const year_month& y) NOEXCEPT  
2254 -{  
2255 - return y < x;  
2256 -}  
2257 -  
2258 -CONSTCD11  
2259 -inline  
2260 -bool  
2261 -operator<=(const year_month& x, const year_month& y) NOEXCEPT  
2262 -{  
2263 - return !(y < x);  
2264 -}  
2265 -  
2266 -CONSTCD11  
2267 -inline  
2268 -bool  
2269 -operator>=(const year_month& x, const year_month& y) NOEXCEPT  
2270 -{  
2271 - return !(x < y);  
2272 -}  
2273 -  
2274 -template<class>  
2275 -CONSTCD14  
2276 -inline  
2277 -year_month  
2278 -operator+(const year_month& ym, const months& dm) NOEXCEPT  
2279 -{  
2280 - auto dmi = static_cast<int>(static_cast<unsigned>(ym.month())) - 1 + dm.count();  
2281 - auto dy = (dmi >= 0 ? dmi : dmi-11) / 12;  
2282 - dmi = dmi - dy * 12 + 1;  
2283 - return (ym.year() + years(dy)) / month(static_cast<unsigned>(dmi));  
2284 -}  
2285 -  
2286 -template<class>  
2287 -CONSTCD14  
2288 -inline  
2289 -year_month  
2290 -operator+(const months& dm, const year_month& ym) NOEXCEPT  
2291 -{  
2292 - return ym + dm;  
2293 -}  
2294 -  
2295 -template<class>  
2296 -CONSTCD14  
2297 -inline  
2298 -year_month  
2299 -operator-(const year_month& ym, const months& dm) NOEXCEPT  
2300 -{  
2301 - return ym + -dm;  
2302 -}  
2303 -  
2304 -CONSTCD11  
2305 -inline  
2306 -months  
2307 -operator-(const year_month& x, const year_month& y) NOEXCEPT  
2308 -{  
2309 - return (x.year() - y.year()) +  
2310 - months(static_cast<unsigned>(x.month()) - static_cast<unsigned>(y.month()));  
2311 -}  
2312 -  
2313 -CONSTCD11  
2314 -inline  
2315 -year_month  
2316 -operator+(const year_month& ym, const years& dy) NOEXCEPT  
2317 -{  
2318 - return (ym.year() + dy) / ym.month();  
2319 -}  
2320 -  
2321 -CONSTCD11  
2322 -inline  
2323 -year_month  
2324 -operator+(const years& dy, const year_month& ym) NOEXCEPT  
2325 -{  
2326 - return ym + dy;  
2327 -}  
2328 -  
2329 -CONSTCD11  
2330 -inline  
2331 -year_month  
2332 -operator-(const year_month& ym, const years& dy) NOEXCEPT  
2333 -{  
2334 - return ym + -dy;  
2335 -}  
2336 -  
2337 -namespace detail  
2338 -{  
2339 -  
2340 -template<class CharT, class Traits>  
2341 -std::basic_ostream<CharT, Traits>&  
2342 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const year_month& ym)  
2343 -{  
2344 - low_level_fmt(os, ym.year()) << '/';  
2345 - return low_level_fmt(os, ym.month());  
2346 -}  
2347 -  
2348 -} // namespace detail  
2349 -  
2350 -template<class CharT, class Traits>  
2351 -inline  
2352 -std::basic_ostream<CharT, Traits>&  
2353 -operator<<(std::basic_ostream<CharT, Traits>& os, const year_month& ym)  
2354 -{  
2355 - detail::low_level_fmt(os, ym);  
2356 - if (!ym.ok())  
2357 - os << " is not a valid year_month";  
2358 - return os;  
2359 -}  
2360 -  
2361 -// month_day  
2362 -  
2363 -CONSTCD11  
2364 -inline  
2365 -month_day::month_day(const date::month& m, const date::day& d) NOEXCEPT  
2366 - : m_(m)  
2367 - , d_(d)  
2368 - {}  
2369 -  
2370 -CONSTCD11 inline date::month month_day::month() const NOEXCEPT {return m_;}  
2371 -CONSTCD11 inline date::day month_day::day() const NOEXCEPT {return d_;}  
2372 -  
2373 -CONSTCD14  
2374 -inline  
2375 -bool  
2376 -month_day::ok() const NOEXCEPT  
2377 -{  
2378 - CONSTDATA date::day d[] =  
2379 - {  
2380 - date::day(31), date::day(29), date::day(31),  
2381 - date::day(30), date::day(31), date::day(30),  
2382 - date::day(31), date::day(31), date::day(30),  
2383 - date::day(31), date::day(30), date::day(31)  
2384 - };  
2385 - return m_.ok() && date::day{1} <= d_ && d_ <= d[static_cast<unsigned>(m_)-1];  
2386 -}  
2387 -  
2388 -CONSTCD11  
2389 -inline  
2390 -bool  
2391 -operator==(const month_day& x, const month_day& y) NOEXCEPT  
2392 -{  
2393 - return x.month() == y.month() && x.day() == y.day();  
2394 -}  
2395 -  
2396 -CONSTCD11  
2397 -inline  
2398 -bool  
2399 -operator!=(const month_day& x, const month_day& y) NOEXCEPT  
2400 -{  
2401 - return !(x == y);  
2402 -}  
2403 -  
2404 -CONSTCD11  
2405 -inline  
2406 -bool  
2407 -operator<(const month_day& x, const month_day& y) NOEXCEPT  
2408 -{  
2409 - return x.month() < y.month() ? true  
2410 - : (x.month() > y.month() ? false  
2411 - : (x.day() < y.day()));  
2412 -}  
2413 -  
2414 -CONSTCD11  
2415 -inline  
2416 -bool  
2417 -operator>(const month_day& x, const month_day& y) NOEXCEPT  
2418 -{  
2419 - return y < x;  
2420 -}  
2421 -  
2422 -CONSTCD11  
2423 -inline  
2424 -bool  
2425 -operator<=(const month_day& x, const month_day& y) NOEXCEPT  
2426 -{  
2427 - return !(y < x);  
2428 -}  
2429 -  
2430 -CONSTCD11  
2431 -inline  
2432 -bool  
2433 -operator>=(const month_day& x, const month_day& y) NOEXCEPT  
2434 -{  
2435 - return !(x < y);  
2436 -}  
2437 -  
2438 -namespace detail  
2439 -{  
2440 -  
2441 -template<class CharT, class Traits>  
2442 -std::basic_ostream<CharT, Traits>&  
2443 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_day& md)  
2444 -{  
2445 - low_level_fmt(os, md.month()) << '/';  
2446 - return low_level_fmt(os, md.day());  
2447 -}  
2448 -  
2449 -} // namespace detail  
2450 -  
2451 -template<class CharT, class Traits>  
2452 -inline  
2453 -std::basic_ostream<CharT, Traits>&  
2454 -operator<<(std::basic_ostream<CharT, Traits>& os, const month_day& md)  
2455 -{  
2456 - detail::low_level_fmt(os, md);  
2457 - if (!md.ok())  
2458 - os << " is not a valid month_day";  
2459 - return os;  
2460 -}  
2461 -  
2462 -// month_day_last  
2463 -  
2464 -CONSTCD11 inline month month_day_last::month() const NOEXCEPT {return m_;}  
2465 -CONSTCD11 inline bool month_day_last::ok() const NOEXCEPT {return m_.ok();}  
2466 -CONSTCD11 inline month_day_last::month_day_last(const date::month& m) NOEXCEPT : m_(m) {}  
2467 -  
2468 -CONSTCD11  
2469 -inline  
2470 -bool  
2471 -operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT  
2472 -{  
2473 - return x.month() == y.month();  
2474 -}  
2475 -  
2476 -CONSTCD11  
2477 -inline  
2478 -bool  
2479 -operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT  
2480 -{  
2481 - return !(x == y);  
2482 -}  
2483 -  
2484 -CONSTCD11  
2485 -inline  
2486 -bool  
2487 -operator<(const month_day_last& x, const month_day_last& y) NOEXCEPT  
2488 -{  
2489 - return x.month() < y.month();  
2490 -}  
2491 -  
2492 -CONSTCD11  
2493 -inline  
2494 -bool  
2495 -operator>(const month_day_last& x, const month_day_last& y) NOEXCEPT  
2496 -{  
2497 - return y < x;  
2498 -}  
2499 -  
2500 -CONSTCD11  
2501 -inline  
2502 -bool  
2503 -operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT  
2504 -{  
2505 - return !(y < x);  
2506 -}  
2507 -  
2508 -CONSTCD11  
2509 -inline  
2510 -bool  
2511 -operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT  
2512 -{  
2513 - return !(x < y);  
2514 -}  
2515 -  
2516 -namespace detail  
2517 -{  
2518 -  
2519 -template<class CharT, class Traits>  
2520 -std::basic_ostream<CharT, Traits>&  
2521 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl)  
2522 -{  
2523 - return low_level_fmt(os, mdl.month()) << "/last";  
2524 -}  
2525 -  
2526 -} // namespace detail  
2527 -  
2528 -template<class CharT, class Traits>  
2529 -inline  
2530 -std::basic_ostream<CharT, Traits>&  
2531 -operator<<(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl)  
2532 -{  
2533 - detail::low_level_fmt(os, mdl);  
2534 - if (!mdl.ok())  
2535 - os << " is not a valid month_day_last";  
2536 - return os;  
2537 -}  
2538 -  
2539 -// month_weekday  
2540 -  
2541 -CONSTCD11  
2542 -inline  
2543 -month_weekday::month_weekday(const date::month& m,  
2544 - const date::weekday_indexed& wdi) NOEXCEPT  
2545 - : m_(m)  
2546 - , wdi_(wdi)  
2547 - {}  
2548 -  
2549 -CONSTCD11 inline month month_weekday::month() const NOEXCEPT {return m_;}  
2550 -  
2551 -CONSTCD11  
2552 -inline  
2553 -weekday_indexed  
2554 -month_weekday::weekday_indexed() const NOEXCEPT  
2555 -{  
2556 - return wdi_;  
2557 -}  
2558 -  
2559 -CONSTCD11  
2560 -inline  
2561 -bool  
2562 -month_weekday::ok() const NOEXCEPT  
2563 -{  
2564 - return m_.ok() && wdi_.ok();  
2565 -}  
2566 -  
2567 -CONSTCD11  
2568 -inline  
2569 -bool  
2570 -operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT  
2571 -{  
2572 - return x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed();  
2573 -}  
2574 -  
2575 -CONSTCD11  
2576 -inline  
2577 -bool  
2578 -operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT  
2579 -{  
2580 - return !(x == y);  
2581 -}  
2582 -  
2583 -namespace detail  
2584 -{  
2585 -  
2586 -template<class CharT, class Traits>  
2587 -std::basic_ostream<CharT, Traits>&  
2588 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd)  
2589 -{  
2590 - low_level_fmt(os, mwd.month()) << '/';  
2591 - return low_level_fmt(os, mwd.weekday_indexed());  
2592 -}  
2593 -  
2594 -} // namespace detail  
2595 -  
2596 -template<class CharT, class Traits>  
2597 -inline  
2598 -std::basic_ostream<CharT, Traits>&  
2599 -operator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd)  
2600 -{  
2601 - detail::low_level_fmt(os, mwd);  
2602 - if (!mwd.ok())  
2603 - os << " is not a valid month_weekday";  
2604 - return os;  
2605 -}  
2606 -  
2607 -// month_weekday_last  
2608 -  
2609 -CONSTCD11  
2610 -inline  
2611 -month_weekday_last::month_weekday_last(const date::month& m,  
2612 - const date::weekday_last& wdl) NOEXCEPT  
2613 - : m_(m)  
2614 - , wdl_(wdl)  
2615 - {}  
2616 -  
2617 -CONSTCD11 inline month month_weekday_last::month() const NOEXCEPT {return m_;}  
2618 -  
2619 -CONSTCD11  
2620 -inline  
2621 -weekday_last  
2622 -month_weekday_last::weekday_last() const NOEXCEPT  
2623 -{  
2624 - return wdl_;  
2625 -}  
2626 -  
2627 -CONSTCD11  
2628 -inline  
2629 -bool  
2630 -month_weekday_last::ok() const NOEXCEPT  
2631 -{  
2632 - return m_.ok() && wdl_.ok();  
2633 -}  
2634 -  
2635 -CONSTCD11  
2636 -inline  
2637 -bool  
2638 -operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT  
2639 -{  
2640 - return x.month() == y.month() && x.weekday_last() == y.weekday_last();  
2641 -}  
2642 -  
2643 -CONSTCD11  
2644 -inline  
2645 -bool  
2646 -operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT  
2647 -{  
2648 - return !(x == y);  
2649 -}  
2650 -  
2651 -namespace detail  
2652 -{  
2653 -  
2654 -template<class CharT, class Traits>  
2655 -std::basic_ostream<CharT, Traits>&  
2656 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl)  
2657 -{  
2658 - low_level_fmt(os, mwdl.month()) << '/';  
2659 - return low_level_fmt(os, mwdl.weekday_last());  
2660 -}  
2661 -  
2662 -} // namespace detail  
2663 -  
2664 -template<class CharT, class Traits>  
2665 -inline  
2666 -std::basic_ostream<CharT, Traits>&  
2667 -operator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl)  
2668 -{  
2669 - detail::low_level_fmt(os, mwdl);  
2670 - if (!mwdl.ok())  
2671 - os << " is not a valid month_weekday_last";  
2672 - return os;  
2673 -}  
2674 -  
2675 -// year_month_day_last  
2676 -  
2677 -CONSTCD11  
2678 -inline  
2679 -year_month_day_last::year_month_day_last(const date::year& y,  
2680 - const date::month_day_last& mdl) NOEXCEPT  
2681 - : y_(y)  
2682 - , mdl_(mdl)  
2683 - {}  
2684 -  
2685 -template<class>  
2686 -CONSTCD14  
2687 -inline  
2688 -year_month_day_last&  
2689 -year_month_day_last::operator+=(const months& m) NOEXCEPT  
2690 -{  
2691 - *this = *this + m;  
2692 - return *this;  
2693 -}  
2694 -  
2695 -template<class>  
2696 -CONSTCD14  
2697 -inline  
2698 -year_month_day_last&  
2699 -year_month_day_last::operator-=(const months& m) NOEXCEPT  
2700 -{  
2701 - *this = *this - m;  
2702 - return *this;  
2703 -}  
2704 -  
2705 -CONSTCD14  
2706 -inline  
2707 -year_month_day_last&  
2708 -year_month_day_last::operator+=(const years& y) NOEXCEPT  
2709 -{  
2710 - *this = *this + y;  
2711 - return *this;  
2712 -}  
2713 -  
2714 -CONSTCD14  
2715 -inline  
2716 -year_month_day_last&  
2717 -year_month_day_last::operator-=(const years& y) NOEXCEPT  
2718 -{  
2719 - *this = *this - y;  
2720 - return *this;  
2721 -}  
2722 -  
2723 -CONSTCD11 inline year year_month_day_last::year() const NOEXCEPT {return y_;}  
2724 -CONSTCD11 inline month year_month_day_last::month() const NOEXCEPT {return mdl_.month();}  
2725 -  
2726 -CONSTCD11  
2727 -inline  
2728 -month_day_last  
2729 -year_month_day_last::month_day_last() const NOEXCEPT  
2730 -{  
2731 - return mdl_;  
2732 -}  
2733 -  
2734 -CONSTCD14  
2735 -inline  
2736 -day  
2737 -year_month_day_last::day() const NOEXCEPT  
2738 -{  
2739 - CONSTDATA date::day d[] =  
2740 - {  
2741 - date::day(31), date::day(28), date::day(31),  
2742 - date::day(30), date::day(31), date::day(30),  
2743 - date::day(31), date::day(31), date::day(30),  
2744 - date::day(31), date::day(30), date::day(31)  
2745 - };  
2746 - return (month() != February || !y_.is_leap()) && mdl_.ok() ?  
2747 - d[static_cast<unsigned>(month()) - 1] : date::day{29};  
2748 -}  
2749 -  
2750 -CONSTCD14  
2751 -inline  
2752 -year_month_day_last::operator sys_days() const NOEXCEPT  
2753 -{  
2754 - return sys_days(year()/month()/day());  
2755 -}  
2756 -  
2757 -CONSTCD14  
2758 -inline  
2759 -year_month_day_last::operator local_days() const NOEXCEPT  
2760 -{  
2761 - return local_days(year()/month()/day());  
2762 -}  
2763 -  
2764 -CONSTCD11  
2765 -inline  
2766 -bool  
2767 -year_month_day_last::ok() const NOEXCEPT  
2768 -{  
2769 - return y_.ok() && mdl_.ok();  
2770 -}  
2771 -  
2772 -CONSTCD11  
2773 -inline  
2774 -bool  
2775 -operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT  
2776 -{  
2777 - return x.year() == y.year() && x.month_day_last() == y.month_day_last();  
2778 -}  
2779 -  
2780 -CONSTCD11  
2781 -inline  
2782 -bool  
2783 -operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT  
2784 -{  
2785 - return !(x == y);  
2786 -}  
2787 -  
2788 -CONSTCD11  
2789 -inline  
2790 -bool  
2791 -operator<(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT  
2792 -{  
2793 - return x.year() < y.year() ? true  
2794 - : (x.year() > y.year() ? false  
2795 - : (x.month_day_last() < y.month_day_last()));  
2796 -}  
2797 -  
2798 -CONSTCD11  
2799 -inline  
2800 -bool  
2801 -operator>(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT  
2802 -{  
2803 - return y < x;  
2804 -}  
2805 -  
2806 -CONSTCD11  
2807 -inline  
2808 -bool  
2809 -operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT  
2810 -{  
2811 - return !(y < x);  
2812 -}  
2813 -  
2814 -CONSTCD11  
2815 -inline  
2816 -bool  
2817 -operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT  
2818 -{  
2819 - return !(x < y);  
2820 -}  
2821 -  
2822 -namespace detail  
2823 -{  
2824 -  
2825 -template<class CharT, class Traits>  
2826 -std::basic_ostream<CharT, Traits>&  
2827 -low_level_fmt(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl)  
2828 -{  
2829 - low_level_fmt(os, ymdl.year()) << '/';  
2830 - return low_level_fmt(os, ymdl.month_day_last());  
2831 -}  
2832 -  
2833 -} // namespace detail  
2834 -  
2835 -template<class CharT, class Traits>  
2836 -inline  
2837 -std::basic_ostream<CharT, Traits>&  
2838 -operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl)  
2839 -{  
2840 - detail::low_level_fmt(os, ymdl);  
2841 - if (!ymdl.ok())  
2842 - os << " is not a valid year_month_day_last";  
2843 - return os;  
2844 -}  
2845 -  
2846 -template<class>  
2847 -CONSTCD14  
2848 -inline  
2849 -year_month_day_last  
2850 -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT  
2851 -{  
2852 - return (ymdl.year() / ymdl.month() + dm) / last;  
2853 -}  
2854 -  
2855 -template<class>  
2856 -CONSTCD14  
2857 -inline  
2858 -year_month_day_last  
2859 -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT  
2860 -{  
2861 - return ymdl + dm;  
2862 -}  
2863 -  
2864 -template<class>  
2865 -CONSTCD14  
2866 -inline  
2867 -year_month_day_last  
2868 -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT  
2869 -{  
2870 - return ymdl + (-dm);  
2871 -}  
2872 -  
2873 -CONSTCD11  
2874 -inline  
2875 -year_month_day_last  
2876 -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT  
2877 -{  
2878 - return {ymdl.year()+dy, ymdl.month_day_last()};  
2879 -}  
2880 -  
2881 -CONSTCD11  
2882 -inline  
2883 -year_month_day_last  
2884 -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT  
2885 -{  
2886 - return ymdl + dy;  
2887 -}  
2888 -  
2889 -CONSTCD11  
2890 -inline  
2891 -year_month_day_last  
2892 -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT  
2893 -{  
2894 - return ymdl + (-dy);  
2895 -}  
2896 -  
2897 -// year_month_day  
2898 -  
2899 -CONSTCD11  
2900 -inline  
2901 -year_month_day::year_month_day(const date::year& y, const date::month& m,  
2902 - const date::day& d) NOEXCEPT  
2903 - : y_(y)  
2904 - , m_(m)  
2905 - , d_(d)  
2906 - {}  
2907 -  
2908 -CONSTCD14  
2909 -inline  
2910 -year_month_day::year_month_day(const year_month_day_last& ymdl) NOEXCEPT  
2911 - : y_(ymdl.year())  
2912 - , m_(ymdl.month())  
2913 - , d_(ymdl.day())  
2914 - {}  
2915 -  
2916 -CONSTCD14  
2917 -inline  
2918 -year_month_day::year_month_day(sys_days dp) NOEXCEPT  
2919 - : year_month_day(from_days(dp.time_since_epoch()))  
2920 - {}  
2921 -  
2922 -CONSTCD14  
2923 -inline  
2924 -year_month_day::year_month_day(local_days dp) NOEXCEPT  
2925 - : year_month_day(from_days(dp.time_since_epoch()))  
2926 - {}  
2927 -  
2928 -CONSTCD11 inline year year_month_day::year() const NOEXCEPT {return y_;}  
2929 -CONSTCD11 inline month year_month_day::month() const NOEXCEPT {return m_;}  
2930 -CONSTCD11 inline day year_month_day::day() const NOEXCEPT {return d_;}  
2931 -  
2932 -template<class>  
2933 -CONSTCD14  
2934 -inline  
2935 -year_month_day&  
2936 -year_month_day::operator+=(const months& m) NOEXCEPT  
2937 -{  
2938 - *this = *this + m;  
2939 - return *this;  
2940 -}  
2941 -  
2942 -template<class>  
2943 -CONSTCD14  
2944 -inline  
2945 -year_month_day&  
2946 -year_month_day::operator-=(const months& m) NOEXCEPT  
2947 -{  
2948 - *this = *this - m;  
2949 - return *this;  
2950 -}  
2951 -  
2952 -CONSTCD14  
2953 -inline  
2954 -year_month_day&  
2955 -year_month_day::operator+=(const years& y) NOEXCEPT  
2956 -{  
2957 - *this = *this + y;  
2958 - return *this;  
2959 -}  
2960 -  
2961 -CONSTCD14  
2962 -inline  
2963 -year_month_day&  
2964 -year_month_day::operator-=(const years& y) NOEXCEPT  
2965 -{  
2966 - *this = *this - y;  
2967 - return *this;  
2968 -}  
2969 -  
2970 -CONSTCD14  
2971 -inline  
2972 -days  
2973 -year_month_day::to_days() const NOEXCEPT  
2974 -{  
2975 - static_assert(std::numeric_limits<unsigned>::digits >= 18,  
2976 - "This algorithm has not been ported to a 16 bit unsigned integer");  
2977 - static_assert(std::numeric_limits<int>::digits >= 20,  
2978 - "This algorithm has not been ported to a 16 bit signed integer");  
2979 - auto const y = static_cast<int>(y_) - (m_ <= February);  
2980 - auto const m = static_cast<unsigned>(m_);  
2981 - auto const d = static_cast<unsigned>(d_);  
2982 - auto const era = (y >= 0 ? y : y-399) / 400;  
2983 - auto const yoe = static_cast<unsigned>(y - era * 400); // [0, 399]  
2984 - auto const doy = (153*(m > 2 ? m-3 : m+9) + 2)/5 + d-1; // [0, 365]  
2985 - auto const doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096]  
2986 - return days{era * 146097 + static_cast<int>(doe) - 719468};  
2987 -}  
2988 -  
2989 -CONSTCD14  
2990 -inline  
2991 -year_month_day::operator sys_days() const NOEXCEPT  
2992 -{  
2993 - return sys_days{to_days()};  
2994 -}  
2995 -  
2996 -CONSTCD14  
2997 -inline  
2998 -year_month_day::operator local_days() const NOEXCEPT  
2999 -{  
3000 - return local_days{to_days()};  
3001 -}  
3002 -  
3003 -CONSTCD14  
3004 -inline  
3005 -bool  
3006 -year_month_day::ok() const NOEXCEPT  
3007 -{  
3008 - if (!(y_.ok() && m_.ok()))  
3009 - return false;  
3010 - return date::day{1} <= d_ && d_ <= (y_ / m_ / last).day();  
3011 -}  
3012 -  
3013 -CONSTCD11  
3014 -inline  
3015 -bool  
3016 -operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT  
3017 -{  
3018 - return x.year() == y.year() && x.month() == y.month() && x.day() == y.day();  
3019 -}  
3020 -  
3021 -CONSTCD11  
3022 -inline  
3023 -bool  
3024 -operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT  
3025 -{  
3026 - return !(x == y);  
3027 -}  
3028 -  
3029 -CONSTCD11  
3030 -inline  
3031 -bool  
3032 -operator<(const year_month_day& x, const year_month_day& y) NOEXCEPT  
3033 -{  
3034 - return x.year() < y.year() ? true  
3035 - : (x.year() > y.year() ? false  
3036 - : (x.month() < y.month() ? true  
3037 - : (x.month() > y.month() ? false  
3038 - : (x.day() < y.day()))));  
3039 -}  
3040 -  
3041 -CONSTCD11  
3042 -inline  
3043 -bool  
3044 -operator>(const year_month_day& x, const year_month_day& y) NOEXCEPT  
3045 -{  
3046 - return y < x;  
3047 -}  
3048 -  
3049 -CONSTCD11  
3050 -inline  
3051 -bool  
3052 -operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT  
3053 -{  
3054 - return !(y < x);  
3055 -}  
3056 -  
3057 -CONSTCD11  
3058 -inline  
3059 -bool  
3060 -operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT  
3061 -{  
3062 - return !(x < y);  
3063 -}  
3064 -  
3065 -template<class CharT, class Traits>  
3066 -inline  
3067 -std::basic_ostream<CharT, Traits>&  
3068 -operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd)  
3069 -{  
3070 - detail::save_ostream<CharT, Traits> _(os);  
3071 - os.fill('0');  
3072 - os.flags(std::ios::dec | std::ios::right);  
3073 - os.imbue(std::locale::classic());  
3074 - os << static_cast<int>(ymd.year()) << '-';  
3075 - os.width(2);  
3076 - os << static_cast<unsigned>(ymd.month()) << '-';  
3077 - os.width(2);  
3078 - os << static_cast<unsigned>(ymd.day());  
3079 - if (!ymd.ok())  
3080 - os << " is not a valid year_month_day";  
3081 - return os;  
3082 -}  
3083 -  
3084 -CONSTCD14  
3085 -inline  
3086 -year_month_day  
3087 -year_month_day::from_days(days dp) NOEXCEPT  
3088 -{  
3089 - static_assert(std::numeric_limits<unsigned>::digits >= 18,  
3090 - "This algorithm has not been ported to a 16 bit unsigned integer");  
3091 - static_assert(std::numeric_limits<int>::digits >= 20,  
3092 - "This algorithm has not been ported to a 16 bit signed integer");  
3093 - auto const z = dp.count() + 719468;  
3094 - auto const era = (z >= 0 ? z : z - 146096) / 146097;  
3095 - auto const doe = static_cast<unsigned>(z - era * 146097); // [0, 146096]  
3096 - auto const yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399]  
3097 - auto const y = static_cast<days::rep>(yoe) + era * 400;  
3098 - auto const doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365]  
3099 - auto const mp = (5*doy + 2)/153; // [0, 11]  
3100 - auto const d = doy - (153*mp+2)/5 + 1; // [1, 31]  
3101 - auto const m = mp < 10 ? mp+3 : mp-9; // [1, 12]  
3102 - return year_month_day{date::year{y + (m <= 2)}, date::month(m), date::day(d)};  
3103 -}  
3104 -  
3105 -template<class>  
3106 -CONSTCD14  
3107 -inline  
3108 -year_month_day  
3109 -operator+(const year_month_day& ymd, const months& dm) NOEXCEPT  
3110 -{  
3111 - return (ymd.year() / ymd.month() + dm) / ymd.day();  
3112 -}  
3113 -  
3114 -template<class>  
3115 -CONSTCD14  
3116 -inline  
3117 -year_month_day  
3118 -operator+(const months& dm, const year_month_day& ymd) NOEXCEPT  
3119 -{  
3120 - return ymd + dm;  
3121 -}  
3122 -  
3123 -template<class>  
3124 -CONSTCD14  
3125 -inline  
3126 -year_month_day  
3127 -operator-(const year_month_day& ymd, const months& dm) NOEXCEPT  
3128 -{  
3129 - return ymd + (-dm);  
3130 -}  
3131 -  
3132 -CONSTCD11  
3133 -inline  
3134 -year_month_day  
3135 -operator+(const year_month_day& ymd, const years& dy) NOEXCEPT  
3136 -{  
3137 - return (ymd.year() + dy) / ymd.month() / ymd.day();  
3138 -}  
3139 -  
3140 -CONSTCD11  
3141 -inline  
3142 -year_month_day  
3143 -operator+(const years& dy, const year_month_day& ymd) NOEXCEPT  
3144 -{  
3145 - return ymd + dy;  
3146 -}  
3147 -  
3148 -CONSTCD11  
3149 -inline  
3150 -year_month_day  
3151 -operator-(const year_month_day& ymd, const years& dy) NOEXCEPT  
3152 -{  
3153 - return ymd + (-dy);  
3154 -}  
3155 -  
3156 -// year_month_weekday  
3157 -  
3158 -CONSTCD11  
3159 -inline  
3160 -year_month_weekday::year_month_weekday(const date::year& y, const date::month& m,  
3161 - const date::weekday_indexed& wdi)  
3162 - NOEXCEPT  
3163 - : y_(y)  
3164 - , m_(m)  
3165 - , wdi_(wdi)  
3166 - {}  
3167 -  
3168 -CONSTCD14  
3169 -inline  
3170 -year_month_weekday::year_month_weekday(const sys_days& dp) NOEXCEPT  
3171 - : year_month_weekday(from_days(dp.time_since_epoch()))  
3172 - {}  
3173 -  
3174 -CONSTCD14  
3175 -inline  
3176 -year_month_weekday::year_month_weekday(const local_days& dp) NOEXCEPT  
3177 - : year_month_weekday(from_days(dp.time_since_epoch()))  
3178 - {}  
3179 -  
3180 -template<class>  
3181 -CONSTCD14  
3182 -inline  
3183 -year_month_weekday&  
3184 -year_month_weekday::operator+=(const months& m) NOEXCEPT  
3185 -{  
3186 - *this = *this + m;  
3187 - return *this;  
3188 -}  
3189 -  
3190 -template<class>  
3191 -CONSTCD14  
3192 -inline  
3193 -year_month_weekday&  
3194 -year_month_weekday::operator-=(const months& m) NOEXCEPT  
3195 -{  
3196 - *this = *this - m;  
3197 - return *this;  
3198 -}  
3199 -  
3200 -CONSTCD14  
3201 -inline  
3202 -year_month_weekday&  
3203 -year_month_weekday::operator+=(const years& y) NOEXCEPT  
3204 -{  
3205 - *this = *this + y;  
3206 - return *this;  
3207 -}  
3208 -  
3209 -CONSTCD14  
3210 -inline  
3211 -year_month_weekday&  
3212 -year_month_weekday::operator-=(const years& y) NOEXCEPT  
3213 -{  
3214 - *this = *this - y;  
3215 - return *this;  
3216 -}  
3217 -  
3218 -CONSTCD11 inline year year_month_weekday::year() const NOEXCEPT {return y_;}  
3219 -CONSTCD11 inline month year_month_weekday::month() const NOEXCEPT {return m_;}  
3220 -  
3221 -CONSTCD11  
3222 -inline  
3223 -weekday  
3224 -year_month_weekday::weekday() const NOEXCEPT  
3225 -{  
3226 - return wdi_.weekday();  
3227 -}  
3228 -  
3229 -CONSTCD11  
3230 -inline  
3231 -unsigned  
3232 -year_month_weekday::index() const NOEXCEPT  
3233 -{  
3234 - return wdi_.index();  
3235 -}  
3236 -  
3237 -CONSTCD11  
3238 -inline  
3239 -weekday_indexed  
3240 -year_month_weekday::weekday_indexed() const NOEXCEPT  
3241 -{  
3242 - return wdi_;  
3243 -}  
3244 -  
3245 -CONSTCD14  
3246 -inline  
3247 -year_month_weekday::operator sys_days() const NOEXCEPT  
3248 -{  
3249 - return sys_days{to_days()};  
3250 -}  
3251 -  
3252 -CONSTCD14  
3253 -inline  
3254 -year_month_weekday::operator local_days() const NOEXCEPT  
3255 -{  
3256 - return local_days{to_days()};  
3257 -}  
3258 -  
3259 -CONSTCD14  
3260 -inline  
3261 -bool  
3262 -year_month_weekday::ok() const NOEXCEPT  
3263 -{  
3264 - if (!y_.ok() || !m_.ok() || !wdi_.weekday().ok() || wdi_.index() < 1)  
3265 - return false;  
3266 - if (wdi_.index() <= 4)  
3267 - return true;  
3268 - auto d2 = wdi_.weekday() - date::weekday(static_cast<sys_days>(y_/m_/1)) +  
3269 - days((wdi_.index()-1)*7 + 1);  
3270 - return static_cast<unsigned>(d2.count()) <= static_cast<unsigned>((y_/m_/last).day());  
3271 -}  
3272 -  
3273 -CONSTCD14  
3274 -inline  
3275 -year_month_weekday  
3276 -year_month_weekday::from_days(days d) NOEXCEPT  
3277 -{  
3278 - sys_days dp{d};  
3279 - auto const wd = date::weekday(dp);  
3280 - auto const ymd = year_month_day(dp);  
3281 - return {ymd.year(), ymd.month(), wd[(static_cast<unsigned>(ymd.day())-1)/7+1]};  
3282 -}  
3283 -  
3284 -CONSTCD14  
3285 -inline  
3286 -days  
3287 -year_month_weekday::to_days() const NOEXCEPT  
3288 -{  
3289 - auto d = sys_days(y_/m_/1);  
3290 - return (d + (wdi_.weekday() - date::weekday(d) + days{(wdi_.index()-1)*7})  
3291 - ).time_since_epoch();  
3292 -}  
3293 -  
3294 -CONSTCD11  
3295 -inline  
3296 -bool  
3297 -operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT  
3298 -{  
3299 - return x.year() == y.year() && x.month() == y.month() &&  
3300 - x.weekday_indexed() == y.weekday_indexed();  
3301 -}  
3302 -  
3303 -CONSTCD11  
3304 -inline  
3305 -bool  
3306 -operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT  
3307 -{  
3308 - return !(x == y);  
3309 -}  
3310 -  
3311 -template<class CharT, class Traits>  
3312 -inline  
3313 -std::basic_ostream<CharT, Traits>&  
3314 -operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday& ymwdi)  
3315 -{  
3316 - detail::low_level_fmt(os, ymwdi.year()) << '/';  
3317 - detail::low_level_fmt(os, ymwdi.month()) << '/';  
3318 - detail::low_level_fmt(os, ymwdi.weekday_indexed());  
3319 - if (!ymwdi.ok())  
3320 - os << " is not a valid year_month_weekday";  
3321 - return os;  
3322 -}  
3323 -  
3324 -template<class>  
3325 -CONSTCD14  
3326 -inline  
3327 -year_month_weekday  
3328 -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT  
3329 -{  
3330 - return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed();  
3331 -}  
3332 -  
3333 -template<class>  
3334 -CONSTCD14  
3335 -inline  
3336 -year_month_weekday  
3337 -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT  
3338 -{  
3339 - return ymwd + dm;  
3340 -}  
3341 -  
3342 -template<class>  
3343 -CONSTCD14  
3344 -inline  
3345 -year_month_weekday  
3346 -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT  
3347 -{  
3348 - return ymwd + (-dm);  
3349 -}  
3350 -  
3351 -CONSTCD11  
3352 -inline  
3353 -year_month_weekday  
3354 -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT  
3355 -{  
3356 - return {ymwd.year()+dy, ymwd.month(), ymwd.weekday_indexed()};  
3357 -}  
3358 -  
3359 -CONSTCD11  
3360 -inline  
3361 -year_month_weekday  
3362 -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT  
3363 -{  
3364 - return ymwd + dy;  
3365 -}  
3366 -  
3367 -CONSTCD11  
3368 -inline  
3369 -year_month_weekday  
3370 -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT  
3371 -{  
3372 - return ymwd + (-dy);  
3373 -}  
3374 -  
3375 -// year_month_weekday_last  
3376 -  
3377 -CONSTCD11  
3378 -inline  
3379 -year_month_weekday_last::year_month_weekday_last(const date::year& y,  
3380 - const date::month& m,  
3381 - const date::weekday_last& wdl) NOEXCEPT  
3382 - : y_(y)  
3383 - , m_(m)  
3384 - , wdl_(wdl)  
3385 - {}  
3386 -  
3387 -template<class>  
3388 -CONSTCD14  
3389 -inline  
3390 -year_month_weekday_last&  
3391 -year_month_weekday_last::operator+=(const months& m) NOEXCEPT  
3392 -{  
3393 - *this = *this + m;  
3394 - return *this;  
3395 -}  
3396 -  
3397 -template<class>  
3398 -CONSTCD14  
3399 -inline  
3400 -year_month_weekday_last&  
3401 -year_month_weekday_last::operator-=(const months& m) NOEXCEPT  
3402 -{  
3403 - *this = *this - m;  
3404 - return *this;  
3405 -}  
3406 -  
3407 -CONSTCD14  
3408 -inline  
3409 -year_month_weekday_last&  
3410 -year_month_weekday_last::operator+=(const years& y) NOEXCEPT  
3411 -{  
3412 - *this = *this + y;  
3413 - return *this;  
3414 -}  
3415 -  
3416 -CONSTCD14  
3417 -inline  
3418 -year_month_weekday_last&  
3419 -year_month_weekday_last::operator-=(const years& y) NOEXCEPT  
3420 -{  
3421 - *this = *this - y;  
3422 - return *this;  
3423 -}  
3424 -  
3425 -CONSTCD11 inline year year_month_weekday_last::year() const NOEXCEPT {return y_;}  
3426 -CONSTCD11 inline month year_month_weekday_last::month() const NOEXCEPT {return m_;}  
3427 -  
3428 -CONSTCD11  
3429 -inline  
3430 -weekday  
3431 -year_month_weekday_last::weekday() const NOEXCEPT  
3432 -{  
3433 - return wdl_.weekday();  
3434 -}  
3435 -  
3436 -CONSTCD11  
3437 -inline  
3438 -weekday_last  
3439 -year_month_weekday_last::weekday_last() const NOEXCEPT  
3440 -{  
3441 - return wdl_;  
3442 -}  
3443 -  
3444 -CONSTCD14  
3445 -inline  
3446 -year_month_weekday_last::operator sys_days() const NOEXCEPT  
3447 -{  
3448 - return sys_days{to_days()};  
3449 -}  
3450 -  
3451 -CONSTCD14  
3452 -inline  
3453 -year_month_weekday_last::operator local_days() const NOEXCEPT  
3454 -{  
3455 - return local_days{to_days()};  
3456 -}  
3457 -  
3458 -CONSTCD11  
3459 -inline  
3460 -bool  
3461 -year_month_weekday_last::ok() const NOEXCEPT  
3462 -{  
3463 - return y_.ok() && m_.ok() && wdl_.ok();  
3464 -}  
3465 -  
3466 -CONSTCD14  
3467 -inline  
3468 -days  
3469 -year_month_weekday_last::to_days() const NOEXCEPT  
3470 -{  
3471 - auto const d = sys_days(y_/m_/last);  
3472 - return (d - (date::weekday{d} - wdl_.weekday())).time_since_epoch();  
3473 -}  
3474 -  
3475 -CONSTCD11  
3476 -inline  
3477 -bool  
3478 -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT  
3479 -{  
3480 - return x.year() == y.year() && x.month() == y.month() &&  
3481 - x.weekday_last() == y.weekday_last();  
3482 -}  
3483 -  
3484 -CONSTCD11  
3485 -inline  
3486 -bool  
3487 -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT  
3488 -{  
3489 - return !(x == y);  
3490 -}  
3491 -  
3492 -template<class CharT, class Traits>  
3493 -inline  
3494 -std::basic_ostream<CharT, Traits>&  
3495 -operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday_last& ymwdl)  
3496 -{  
3497 - detail::low_level_fmt(os, ymwdl.year()) << '/';  
3498 - detail::low_level_fmt(os, ymwdl.month()) << '/';  
3499 - detail::low_level_fmt(os, ymwdl.weekday_last());  
3500 - if (!ymwdl.ok())  
3501 - os << " is not a valid year_month_weekday_last";  
3502 - return os;  
3503 -}  
3504 -  
3505 -template<class>  
3506 -CONSTCD14  
3507 -inline  
3508 -year_month_weekday_last  
3509 -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT  
3510 -{  
3511 - return (ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last();  
3512 -}  
3513 -  
3514 -template<class>  
3515 -CONSTCD14  
3516 -inline  
3517 -year_month_weekday_last  
3518 -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT  
3519 -{  
3520 - return ymwdl + dm;  
3521 -}  
3522 -  
3523 -template<class>  
3524 -CONSTCD14  
3525 -inline  
3526 -year_month_weekday_last  
3527 -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT  
3528 -{  
3529 - return ymwdl + (-dm);  
3530 -}  
3531 -  
3532 -CONSTCD11  
3533 -inline  
3534 -year_month_weekday_last  
3535 -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT  
3536 -{  
3537 - return {ymwdl.year()+dy, ymwdl.month(), ymwdl.weekday_last()};  
3538 -}  
3539 -  
3540 -CONSTCD11  
3541 -inline  
3542 -year_month_weekday_last  
3543 -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT  
3544 -{  
3545 - return ymwdl + dy;  
3546 -}  
3547 -  
3548 -CONSTCD11  
3549 -inline  
3550 -year_month_weekday_last  
3551 -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT  
3552 -{  
3553 - return ymwdl + (-dy);  
3554 -}  
3555 -  
3556 -// year_month from operator/()  
3557 -  
3558 -CONSTCD11  
3559 -inline  
3560 -year_month  
3561 -operator/(const year& y, const month& m) NOEXCEPT  
3562 -{  
3563 - return {y, m};  
3564 -}  
3565 -  
3566 -CONSTCD11  
3567 -inline  
3568 -year_month  
3569 -operator/(const year& y, int m) NOEXCEPT  
3570 -{  
3571 - return y / month(static_cast<unsigned>(m));  
3572 -}  
3573 -  
3574 -// month_day from operator/()  
3575 -  
3576 -CONSTCD11  
3577 -inline  
3578 -month_day  
3579 -operator/(const month& m, const day& d) NOEXCEPT  
3580 -{  
3581 - return {m, d};  
3582 -}  
3583 -  
3584 -CONSTCD11  
3585 -inline  
3586 -month_day  
3587 -operator/(const day& d, const month& m) NOEXCEPT  
3588 -{  
3589 - return m / d;  
3590 -}  
3591 -  
3592 -CONSTCD11  
3593 -inline  
3594 -month_day  
3595 -operator/(const month& m, int d) NOEXCEPT  
3596 -{  
3597 - return m / day(static_cast<unsigned>(d));  
3598 -}  
3599 -  
3600 -CONSTCD11  
3601 -inline  
3602 -month_day  
3603 -operator/(int m, const day& d) NOEXCEPT  
3604 -{  
3605 - return month(static_cast<unsigned>(m)) / d;  
3606 -}  
3607 -  
3608 -CONSTCD11 inline month_day operator/(const day& d, int m) NOEXCEPT {return m / d;}  
3609 -  
3610 -// month_day_last from operator/()  
3611 -  
3612 -CONSTCD11  
3613 -inline  
3614 -month_day_last  
3615 -operator/(const month& m, last_spec) NOEXCEPT  
3616 -{  
3617 - return month_day_last{m};  
3618 -}  
3619 -  
3620 -CONSTCD11  
3621 -inline  
3622 -month_day_last  
3623 -operator/(last_spec, const month& m) NOEXCEPT  
3624 -{  
3625 - return m/last;  
3626 -}  
3627 -  
3628 -CONSTCD11  
3629 -inline  
3630 -month_day_last  
3631 -operator/(int m, last_spec) NOEXCEPT  
3632 -{  
3633 - return month(static_cast<unsigned>(m))/last;  
3634 -}  
3635 -  
3636 -CONSTCD11  
3637 -inline  
3638 -month_day_last  
3639 -operator/(last_spec, int m) NOEXCEPT  
3640 -{  
3641 - return m/last;  
3642 -}  
3643 -  
3644 -// month_weekday from operator/()  
3645 -  
3646 -CONSTCD11  
3647 -inline  
3648 -month_weekday  
3649 -operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT  
3650 -{  
3651 - return {m, wdi};  
3652 -}  
3653 -  
3654 -CONSTCD11  
3655 -inline  
3656 -month_weekday  
3657 -operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT  
3658 -{  
3659 - return m / wdi;  
3660 -}  
3661 -  
3662 -CONSTCD11  
3663 -inline  
3664 -month_weekday  
3665 -operator/(int m, const weekday_indexed& wdi) NOEXCEPT  
3666 -{  
3667 - return month(static_cast<unsigned>(m)) / wdi;  
3668 -}  
3669 -  
3670 -CONSTCD11  
3671 -inline  
3672 -month_weekday  
3673 -operator/(const weekday_indexed& wdi, int m) NOEXCEPT  
3674 -{  
3675 - return m / wdi;  
3676 -}  
3677 -  
3678 -// month_weekday_last from operator/()  
3679 -  
3680 -CONSTCD11  
3681 -inline  
3682 -month_weekday_last  
3683 -operator/(const month& m, const weekday_last& wdl) NOEXCEPT  
3684 -{  
3685 - return {m, wdl};  
3686 -}  
3687 -  
3688 -CONSTCD11  
3689 -inline  
3690 -month_weekday_last  
3691 -operator/(const weekday_last& wdl, const month& m) NOEXCEPT  
3692 -{  
3693 - return m / wdl;  
3694 -}  
3695 -  
3696 -CONSTCD11  
3697 -inline  
3698 -month_weekday_last  
3699 -operator/(int m, const weekday_last& wdl) NOEXCEPT  
3700 -{  
3701 - return month(static_cast<unsigned>(m)) / wdl;  
3702 -}  
3703 -  
3704 -CONSTCD11  
3705 -inline  
3706 -month_weekday_last  
3707 -operator/(const weekday_last& wdl, int m) NOEXCEPT  
3708 -{  
3709 - return m / wdl;  
3710 -}  
3711 -  
3712 -// year_month_day from operator/()  
3713 -  
3714 -CONSTCD11  
3715 -inline  
3716 -year_month_day  
3717 -operator/(const year_month& ym, const day& d) NOEXCEPT  
3718 -{  
3719 - return {ym.year(), ym.month(), d};  
3720 -}  
3721 -  
3722 -CONSTCD11  
3723 -inline  
3724 -year_month_day  
3725 -operator/(const year_month& ym, int d) NOEXCEPT  
3726 -{  
3727 - return ym / day(static_cast<unsigned>(d));  
3728 -}  
3729 -  
3730 -CONSTCD11  
3731 -inline  
3732 -year_month_day  
3733 -operator/(const year& y, const month_day& md) NOEXCEPT  
3734 -{  
3735 - return y / md.month() / md.day();  
3736 -}  
3737 -  
3738 -CONSTCD11  
3739 -inline  
3740 -year_month_day  
3741 -operator/(int y, const month_day& md) NOEXCEPT  
3742 -{  
3743 - return year(y) / md;  
3744 -}  
3745 -  
3746 -CONSTCD11  
3747 -inline  
3748 -year_month_day  
3749 -operator/(const month_day& md, const year& y) NOEXCEPT  
3750 -{  
3751 - return y / md;  
3752 -}  
3753 -  
3754 -CONSTCD11  
3755 -inline  
3756 -year_month_day  
3757 -operator/(const month_day& md, int y) NOEXCEPT  
3758 -{  
3759 - return year(y) / md;  
3760 -}  
3761 -  
3762 -// year_month_day_last from operator/()  
3763 -  
3764 -CONSTCD11  
3765 -inline  
3766 -year_month_day_last  
3767 -operator/(const year_month& ym, last_spec) NOEXCEPT  
3768 -{  
3769 - return {ym.year(), month_day_last{ym.month()}};  
3770 -}  
3771 -  
3772 -CONSTCD11  
3773 -inline  
3774 -year_month_day_last  
3775 -operator/(const year& y, const month_day_last& mdl) NOEXCEPT  
3776 -{  
3777 - return {y, mdl};  
3778 -}  
3779 -  
3780 -CONSTCD11  
3781 -inline  
3782 -year_month_day_last  
3783 -operator/(int y, const month_day_last& mdl) NOEXCEPT  
3784 -{  
3785 - return year(y) / mdl;  
3786 -}  
3787 -  
3788 -CONSTCD11  
3789 -inline  
3790 -year_month_day_last  
3791 -operator/(const month_day_last& mdl, const year& y) NOEXCEPT  
3792 -{  
3793 - return y / mdl;  
3794 -}  
3795 -  
3796 -CONSTCD11  
3797 -inline  
3798 -year_month_day_last  
3799 -operator/(const month_day_last& mdl, int y) NOEXCEPT  
3800 -{  
3801 - return year(y) / mdl;  
3802 -}  
3803 -  
3804 -// year_month_weekday from operator/()  
3805 -  
3806 -CONSTCD11  
3807 -inline  
3808 -year_month_weekday  
3809 -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT  
3810 -{  
3811 - return {ym.year(), ym.month(), wdi};  
3812 -}  
3813 -  
3814 -CONSTCD11  
3815 -inline  
3816 -year_month_weekday  
3817 -operator/(const year& y, const month_weekday& mwd) NOEXCEPT  
3818 -{  
3819 - return {y, mwd.month(), mwd.weekday_indexed()};  
3820 -}  
3821 -  
3822 -CONSTCD11  
3823 -inline  
3824 -year_month_weekday  
3825 -operator/(int y, const month_weekday& mwd) NOEXCEPT  
3826 -{  
3827 - return year(y) / mwd;  
3828 -}  
3829 -  
3830 -CONSTCD11  
3831 -inline  
3832 -year_month_weekday  
3833 -operator/(const month_weekday& mwd, const year& y) NOEXCEPT  
3834 -{  
3835 - return y / mwd;  
3836 -}  
3837 -  
3838 -CONSTCD11  
3839 -inline  
3840 -year_month_weekday  
3841 -operator/(const month_weekday& mwd, int y) NOEXCEPT  
3842 -{  
3843 - return year(y) / mwd;  
3844 -}  
3845 -  
3846 -// year_month_weekday_last from operator/()  
3847 -  
3848 -CONSTCD11  
3849 -inline  
3850 -year_month_weekday_last  
3851 -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT  
3852 -{  
3853 - return {ym.year(), ym.month(), wdl};  
3854 -}  
3855 -  
3856 -CONSTCD11  
3857 -inline  
3858 -year_month_weekday_last  
3859 -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT  
3860 -{  
3861 - return {y, mwdl.month(), mwdl.weekday_last()};  
3862 -}  
3863 -  
3864 -CONSTCD11  
3865 -inline  
3866 -year_month_weekday_last  
3867 -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT  
3868 -{  
3869 - return year(y) / mwdl;  
3870 -}  
3871 -  
3872 -CONSTCD11  
3873 -inline  
3874 -year_month_weekday_last  
3875 -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT  
3876 -{  
3877 - return y / mwdl;  
3878 -}  
3879 -  
3880 -CONSTCD11  
3881 -inline  
3882 -year_month_weekday_last  
3883 -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT  
3884 -{  
3885 - return year(y) / mwdl;  
3886 -}  
3887 -  
3888 -template <class Duration>  
3889 -struct fields;  
3890 -  
3891 -template <class CharT, class Traits, class Duration>  
3892 -std::basic_ostream<CharT, Traits>&  
3893 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,  
3894 - const fields<Duration>& fds, const std::string* abbrev = nullptr,  
3895 - const std::chrono::seconds* offset_sec = nullptr);  
3896 -  
3897 -template <class CharT, class Traits, class Duration, class Alloc>  
3898 -std::basic_istream<CharT, Traits>&  
3899 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,  
3900 - fields<Duration>& fds, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
3901 - std::chrono::minutes* offset = nullptr);  
3902 -  
3903 -// hh_mm_ss  
3904 -  
3905 -namespace detail  
3906 -{  
3907 -  
3908 -struct undocumented {explicit undocumented() = default;};  
3909 -  
3910 -// width<n>::value is the number of fractional decimal digits in 1/n  
3911 -// width<0>::value and width<1>::value are defined to be 0  
3912 -// If 1/n takes more than 18 fractional decimal digits,  
3913 -// the result is truncated to 19.  
3914 -// Example: width<2>::value == 1  
3915 -// Example: width<3>::value == 19  
3916 -// Example: width<4>::value == 2  
3917 -// Example: width<10>::value == 1  
3918 -// Example: width<1000>::value == 3  
3919 -template <std::uint64_t n, std::uint64_t d, unsigned w = 0,  
3920 - bool should_continue = n%d != 0 && (w < 19)>  
3921 -struct width  
3922 -{  
3923 - static_assert(d > 0, "width called with zero denominator");  
3924 - static CONSTDATA unsigned value = 1 + width<n%d*10, d, w+1>::value;  
3925 -};  
3926 -  
3927 -template <std::uint64_t n, std::uint64_t d, unsigned w>  
3928 -struct width<n, d, w, false>  
3929 -{  
3930 - static CONSTDATA unsigned value = 0;  
3931 -};  
3932 -  
3933 -template <unsigned exp>  
3934 -struct static_pow10  
3935 -{  
3936 -private:  
3937 - static CONSTDATA std::uint64_t h = static_pow10<exp/2>::value;  
3938 -public:  
3939 - static CONSTDATA std::uint64_t value = h * h * (exp % 2 ? 10 : 1);  
3940 -};  
3941 -  
3942 -template <>  
3943 -struct static_pow10<0>  
3944 -{  
3945 - static CONSTDATA std::uint64_t value = 1;  
3946 -};  
3947 -  
3948 -template <class Duration>  
3949 -class decimal_format_seconds  
3950 -{  
3951 - using CT = typename std::common_type<Duration, std::chrono::seconds>::type;  
3952 - using rep = typename CT::rep;  
3953 - static unsigned CONSTDATA trial_width =  
3954 - detail::width<CT::period::num, CT::period::den>::value;  
3955 -public:  
3956 - static unsigned CONSTDATA width = trial_width < 19 ? trial_width : 6u;  
3957 - using precision = std::chrono::duration<rep,  
3958 - std::ratio<1, static_pow10<width>::value>>;  
3959 -  
3960 -private:  
3961 - std::chrono::seconds s_;  
3962 - precision sub_s_;  
3963 -  
3964 -public:  
3965 - CONSTCD11 decimal_format_seconds()  
3966 - : s_()  
3967 - , sub_s_()  
3968 - {}  
3969 -  
3970 - CONSTCD11 explicit decimal_format_seconds(const Duration& d) NOEXCEPT  
3971 - : s_(std::chrono::duration_cast<std::chrono::seconds>(d))  
3972 - , sub_s_(std::chrono::duration_cast<precision>(d - s_))  
3973 - {}  
3974 -  
3975 - CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_;}  
3976 - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_;}  
3977 - CONSTCD11 precision subseconds() const NOEXCEPT {return sub_s_;}  
3978 -  
3979 - CONSTCD14 precision to_duration() const NOEXCEPT  
3980 - {  
3981 - return s_ + sub_s_;  
3982 - }  
3983 -  
3984 - CONSTCD11 bool in_conventional_range() const NOEXCEPT  
3985 - {  
3986 - return sub_s_ < std::chrono::seconds{1} && s_ < std::chrono::minutes{1};  
3987 - }  
3988 -  
3989 - template <class CharT, class Traits>  
3990 - friend  
3991 - std::basic_ostream<CharT, Traits>&  
3992 - operator<<(std::basic_ostream<CharT, Traits>& os, const decimal_format_seconds& x)  
3993 - {  
3994 - return x.print(os, std::chrono::treat_as_floating_point<rep>{});  
3995 - }  
3996 -  
3997 - template <class CharT, class Traits>  
3998 - std::basic_ostream<CharT, Traits>&  
3999 - print(std::basic_ostream<CharT, Traits>& os, std::true_type) const  
4000 - {  
4001 - date::detail::save_ostream<CharT, Traits> _(os);  
4002 - std::chrono::duration<rep> d = s_ + sub_s_;  
4003 - if (d < std::chrono::seconds{10})  
4004 - os << '0';  
4005 - os.precision(width+6);  
4006 - os << std::fixed << d.count();  
4007 - return os;  
4008 - }  
4009 -  
4010 - template <class CharT, class Traits>  
4011 - std::basic_ostream<CharT, Traits>&  
4012 - print(std::basic_ostream<CharT, Traits>& os, std::false_type) const  
4013 - {  
4014 - date::detail::save_ostream<CharT, Traits> _(os);  
4015 - os.fill('0');  
4016 - os.flags(std::ios::dec | std::ios::right);  
4017 - os.width(2);  
4018 - os << s_.count();  
4019 - if (width > 0)  
4020 - {  
4021 -#if !ONLY_C_LOCALE  
4022 - os << std::use_facet<std::numpunct<CharT>>(os.getloc()).decimal_point();  
4023 -#else  
4024 - os << '.';  
4025 -#endif  
4026 - date::detail::save_ostream<CharT, Traits> _s(os);  
4027 - os.imbue(std::locale::classic());  
4028 - os.width(width);  
4029 - os << sub_s_.count();  
4030 - }  
4031 - return os;  
4032 - }  
4033 -};  
4034 -  
4035 -template <class Rep, class Period>  
4036 -inline  
4037 -CONSTCD11  
4038 -typename std::enable_if  
4039 - <  
4040 - std::numeric_limits<Rep>::is_signed,  
4041 - std::chrono::duration<Rep, Period>  
4042 - >::type  
4043 -abs(std::chrono::duration<Rep, Period> d)  
4044 -{  
4045 - return d >= d.zero() ? +d : -d;  
4046 -}  
4047 -  
4048 -template <class Rep, class Period>  
4049 -inline  
4050 -CONSTCD11  
4051 -typename std::enable_if  
4052 - <  
4053 - !std::numeric_limits<Rep>::is_signed,  
4054 - std::chrono::duration<Rep, Period>  
4055 - >::type  
4056 -abs(std::chrono::duration<Rep, Period> d)  
4057 -{  
4058 - return d;  
4059 -}  
4060 -  
4061 -} // namespace detail  
4062 -  
4063 -template <class Duration>  
4064 -class hh_mm_ss  
4065 -{  
4066 - using dfs = detail::decimal_format_seconds<typename std::common_type<Duration,  
4067 - std::chrono::seconds>::type>;  
4068 -  
4069 - std::chrono::hours h_;  
4070 - std::chrono::minutes m_;  
4071 - dfs s_;  
4072 - bool neg_;  
4073 -  
4074 -public:  
4075 - static unsigned CONSTDATA fractional_width = dfs::width;  
4076 - using precision = typename dfs::precision;  
4077 -  
4078 - CONSTCD11 hh_mm_ss() NOEXCEPT  
4079 - : hh_mm_ss(Duration::zero())  
4080 - {}  
4081 -  
4082 - CONSTCD11 explicit hh_mm_ss(Duration d) NOEXCEPT  
4083 - : h_(std::chrono::duration_cast<std::chrono::hours>(detail::abs(d)))  
4084 - , m_(std::chrono::duration_cast<std::chrono::minutes>(detail::abs(d)) - h_)  
4085 - , s_(detail::abs(d) - h_ - m_)  
4086 - , neg_(d < Duration::zero())  
4087 - {}  
4088 -  
4089 - CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;}  
4090 - CONSTCD11 std::chrono::minutes minutes() const NOEXCEPT {return m_;}  
4091 - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_.seconds();}  
4092 - CONSTCD14 std::chrono::seconds&  
4093 - seconds(detail::undocumented) NOEXCEPT {return s_.seconds();}  
4094 - CONSTCD11 precision subseconds() const NOEXCEPT {return s_.subseconds();}  
4095 - CONSTCD11 bool is_negative() const NOEXCEPT {return neg_;}  
4096 -  
4097 - CONSTCD11 explicit operator precision() const NOEXCEPT {return to_duration();}  
4098 - CONSTCD11 precision to_duration() const NOEXCEPT  
4099 - {return (s_.to_duration() + m_ + h_) * (1-2*neg_);}  
4100 -  
4101 - CONSTCD11 bool in_conventional_range() const NOEXCEPT  
4102 - {  
4103 - return !neg_ && h_ < days{1} && m_ < std::chrono::hours{1} &&  
4104 - s_.in_conventional_range();  
4105 - }  
4106 -  
4107 -private:  
4108 -  
4109 - template <class charT, class traits>  
4110 - friend  
4111 - std::basic_ostream<charT, traits>&  
4112 - operator<<(std::basic_ostream<charT, traits>& os, hh_mm_ss const& tod)  
4113 - {  
4114 - if (tod.is_negative())  
4115 - os << '-';  
4116 - if (tod.h_ < std::chrono::hours{10})  
4117 - os << '0';  
4118 - os << tod.h_.count() << ':';  
4119 - if (tod.m_ < std::chrono::minutes{10})  
4120 - os << '0';  
4121 - os << tod.m_.count() << ':' << tod.s_;  
4122 - return os;  
4123 - }  
4124 -  
4125 - template <class CharT, class Traits, class Duration2>  
4126 - friend  
4127 - std::basic_ostream<CharT, Traits>&  
4128 - date::to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,  
4129 - const fields<Duration2>& fds, const std::string* abbrev,  
4130 - const std::chrono::seconds* offset_sec);  
4131 -  
4132 - template <class CharT, class Traits, class Duration2, class Alloc>  
4133 - friend  
4134 - std::basic_istream<CharT, Traits>&  
4135 - date::from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,  
4136 - fields<Duration2>& fds,  
4137 - std::basic_string<CharT, Traits, Alloc>* abbrev, std::chrono::minutes* offset);  
4138 -};  
4139 -  
4140 -inline  
4141 -CONSTCD14  
4142 -bool  
4143 -is_am(std::chrono::hours const& h) NOEXCEPT  
4144 -{  
4145 - using std::chrono::hours;  
4146 - return hours{0} <= h && h < hours{12};  
4147 -}  
4148 -  
4149 -inline  
4150 -CONSTCD14  
4151 -bool  
4152 -is_pm(std::chrono::hours const& h) NOEXCEPT  
4153 -{  
4154 - using std::chrono::hours;  
4155 - return hours{12} <= h && h < hours{24};  
4156 -}  
4157 -  
4158 -inline  
4159 -CONSTCD14  
4160 -std::chrono::hours  
4161 -make12(std::chrono::hours h) NOEXCEPT  
4162 -{  
4163 - using std::chrono::hours;  
4164 - if (h < hours{12})  
4165 - {  
4166 - if (h == hours{0})  
4167 - h = hours{12};  
4168 - }  
4169 - else  
4170 - {  
4171 - if (h != hours{12})  
4172 - h = h - hours{12};  
4173 - }  
4174 - return h;  
4175 -}  
4176 -  
4177 -inline  
4178 -CONSTCD14  
4179 -std::chrono::hours  
4180 -make24(std::chrono::hours h, bool is_pm) NOEXCEPT  
4181 -{  
4182 - using std::chrono::hours;  
4183 - if (is_pm)  
4184 - {  
4185 - if (h != hours{12})  
4186 - h = h + hours{12};  
4187 - }  
4188 - else if (h == hours{12})  
4189 - h = hours{0};  
4190 - return h;  
4191 -}  
4192 -  
4193 -template <class Duration>  
4194 -using time_of_day = hh_mm_ss<Duration>;  
4195 -  
4196 -template <class Rep, class Period>  
4197 -CONSTCD11  
4198 -inline  
4199 -hh_mm_ss<std::chrono::duration<Rep, Period>>  
4200 -make_time(const std::chrono::duration<Rep, Period>& d)  
4201 -{  
4202 - return hh_mm_ss<std::chrono::duration<Rep, Period>>(d);  
4203 -}  
4204 -  
4205 -template <class CharT, class Traits, class Duration>  
4206 -inline  
4207 -typename std::enable_if  
4208 -<  
4209 - std::ratio_less<typename Duration::period, days::period>::value  
4210 - , std::basic_ostream<CharT, Traits>&  
4211 ->::type  
4212 -operator<<(std::basic_ostream<CharT, Traits>& os, const sys_time<Duration>& tp)  
4213 -{  
4214 - auto const dp = date::floor<days>(tp);  
4215 - return os << year_month_day(dp) << ' ' << make_time(tp-dp);  
4216 -}  
4217 -  
4218 -template <class CharT, class Traits>  
4219 -inline  
4220 -std::basic_ostream<CharT, Traits>&  
4221 -operator<<(std::basic_ostream<CharT, Traits>& os, const sys_days& dp)  
4222 -{  
4223 - return os << year_month_day(dp);  
4224 -}  
4225 -  
4226 -template <class CharT, class Traits, class Duration>  
4227 -inline  
4228 -std::basic_ostream<CharT, Traits>&  
4229 -operator<<(std::basic_ostream<CharT, Traits>& os, const local_time<Duration>& ut)  
4230 -{  
4231 - return (os << sys_time<Duration>{ut.time_since_epoch()});  
4232 -}  
4233 -  
4234 -namespace detail  
4235 -{  
4236 -  
4237 -template <class CharT, std::size_t N>  
4238 -class string_literal;  
4239 -  
4240 -template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>  
4241 -inline  
4242 -CONSTCD14  
4243 -string_literal<typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type,  
4244 - N1 + N2 - 1>  
4245 -operator+(const string_literal<CharT1, N1>& x, const string_literal<CharT2, N2>& y) NOEXCEPT;  
4246 -  
4247 -template <class CharT, std::size_t N>  
4248 -class string_literal  
4249 -{  
4250 - CharT p_[N];  
4251 -  
4252 - CONSTCD11 string_literal() NOEXCEPT  
4253 - : p_{}  
4254 - {}  
4255 -  
4256 -public:  
4257 - using const_iterator = const CharT*;  
4258 -  
4259 - string_literal(string_literal const&) = default;  
4260 - string_literal& operator=(string_literal const&) = delete;  
4261 -  
4262 - template <std::size_t N1 = 2,  
4263 - class = typename std::enable_if<N1 == N>::type>  
4264 - CONSTCD11 string_literal(CharT c) NOEXCEPT  
4265 - : p_{c}  
4266 - {  
4267 - }  
4268 -  
4269 - template <std::size_t N1 = 3,  
4270 - class = typename std::enable_if<N1 == N>::type>  
4271 - CONSTCD11 string_literal(CharT c1, CharT c2) NOEXCEPT  
4272 - : p_{c1, c2}  
4273 - {  
4274 - }  
4275 -  
4276 - template <std::size_t N1 = 4,  
4277 - class = typename std::enable_if<N1 == N>::type>  
4278 - CONSTCD11 string_literal(CharT c1, CharT c2, CharT c3) NOEXCEPT  
4279 - : p_{c1, c2, c3}  
4280 - {  
4281 - }  
4282 -  
4283 - CONSTCD14 string_literal(const CharT(&a)[N]) NOEXCEPT  
4284 - : p_{}  
4285 - {  
4286 - for (std::size_t i = 0; i < N; ++i)  
4287 - p_[i] = a[i];  
4288 - }  
4289 -  
4290 - template <class U = CharT,  
4291 - class = typename std::enable_if<(1 < sizeof(U))>::type>  
4292 - CONSTCD14 string_literal(const char(&a)[N]) NOEXCEPT  
4293 - : p_{}  
4294 - {  
4295 - for (std::size_t i = 0; i < N; ++i)  
4296 - p_[i] = a[i];  
4297 - }  
4298 -  
4299 - template <class CharT2,  
4300 - class = typename std::enable_if<!std::is_same<CharT2, CharT>::value>::type>  
4301 - CONSTCD14 string_literal(string_literal<CharT2, N> const& a) NOEXCEPT  
4302 - : p_{}  
4303 - {  
4304 - for (std::size_t i = 0; i < N; ++i)  
4305 - p_[i] = a[i];  
4306 - }  
4307 -  
4308 - CONSTCD11 const CharT* data() const NOEXCEPT {return p_;}  
4309 - CONSTCD11 std::size_t size() const NOEXCEPT {return N-1;}  
4310 -  
4311 - CONSTCD11 const_iterator begin() const NOEXCEPT {return p_;}  
4312 - CONSTCD11 const_iterator end() const NOEXCEPT {return p_ + N-1;}  
4313 -  
4314 - CONSTCD11 CharT const& operator[](std::size_t n) const NOEXCEPT  
4315 - {  
4316 - return p_[n];  
4317 - }  
4318 -  
4319 - template <class Traits>  
4320 - friend  
4321 - std::basic_ostream<CharT, Traits>&  
4322 - operator<<(std::basic_ostream<CharT, Traits>& os, const string_literal& s)  
4323 - {  
4324 - return os << s.p_;  
4325 - }  
4326 -  
4327 - template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>  
4328 - friend  
4329 - CONSTCD14  
4330 - string_literal<typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type,  
4331 - N1 + N2 - 1>  
4332 - operator+(const string_literal<CharT1, N1>& x, const string_literal<CharT2, N2>& y) NOEXCEPT;  
4333 -};  
4334 -  
4335 -template <class CharT>  
4336 -CONSTCD11  
4337 -inline  
4338 -string_literal<CharT, 3>  
4339 -operator+(const string_literal<CharT, 2>& x, const string_literal<CharT, 2>& y) NOEXCEPT  
4340 -{  
4341 - return string_literal<CharT, 3>(x[0], y[0]);  
4342 -}  
4343 -  
4344 -template <class CharT>  
4345 -CONSTCD11  
4346 -inline  
4347 -string_literal<CharT, 4>  
4348 -operator+(const string_literal<CharT, 3>& x, const string_literal<CharT, 2>& y) NOEXCEPT  
4349 -{  
4350 - return string_literal<CharT, 4>(x[0], x[1], y[0]);  
4351 -}  
4352 -  
4353 -template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>  
4354 -CONSTCD14  
4355 -inline  
4356 -string_literal<typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type,  
4357 - N1 + N2 - 1>  
4358 -operator+(const string_literal<CharT1, N1>& x, const string_literal<CharT2, N2>& y) NOEXCEPT  
4359 -{  
4360 - using CT = typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type;  
4361 -  
4362 - string_literal<CT, N1 + N2 - 1> r;  
4363 - std::size_t i = 0;  
4364 - for (; i < N1-1; ++i)  
4365 - r.p_[i] = CT(x.p_[i]);  
4366 - for (std::size_t j = 0; j < N2; ++j, ++i)  
4367 - r.p_[i] = CT(y.p_[j]);  
4368 -  
4369 - return r;  
4370 -}  
4371 -  
4372 -  
4373 -template <class CharT, class Traits, class Alloc, std::size_t N>  
4374 -inline  
4375 -std::basic_string<CharT, Traits, Alloc>  
4376 -operator+(std::basic_string<CharT, Traits, Alloc> x, const string_literal<CharT, N>& y)  
4377 -{  
4378 - x.append(y.data(), y.size());  
4379 - return x;  
4380 -}  
4381 -  
4382 -#if __cplusplus >= 201402 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ > 411) \  
4383 - && (!defined(__SUNPRO_CC) || __SUNPRO_CC > 0x5150)  
4384 -  
4385 -template <class CharT,  
4386 - class = std::enable_if_t<std::is_same<CharT, char>::value ||  
4387 - std::is_same<CharT, wchar_t>::value ||  
4388 - std::is_same<CharT, char16_t>::value ||  
4389 - std::is_same<CharT, char32_t>::value>>  
4390 -CONSTCD14  
4391 -inline  
4392 -string_literal<CharT, 2>  
4393 -msl(CharT c) NOEXCEPT  
4394 -{  
4395 - return string_literal<CharT, 2>{c};  
4396 -}  
4397 -  
4398 -CONSTCD14  
4399 -inline  
4400 -std::size_t  
4401 -to_string_len(std::intmax_t i)  
4402 -{  
4403 - std::size_t r = 0;  
4404 - do  
4405 - {  
4406 - i /= 10;  
4407 - ++r;  
4408 - } while (i > 0);  
4409 - return r;  
4410 -}  
4411 -  
4412 -template <std::intmax_t N>  
4413 -CONSTCD14  
4414 -inline  
4415 -std::enable_if_t  
4416 -<  
4417 - N < 10,  
4418 - string_literal<char, to_string_len(N)+1>  
4419 ->  
4420 -msl() NOEXCEPT  
4421 -{  
4422 - return msl(char(N % 10 + '0'));  
4423 -}  
4424 -  
4425 -template <std::intmax_t N>  
4426 -CONSTCD14  
4427 -inline  
4428 -std::enable_if_t  
4429 -<  
4430 - 10 <= N,  
4431 - string_literal<char, to_string_len(N)+1>  
4432 ->  
4433 -msl() NOEXCEPT  
4434 -{  
4435 - return msl<N/10>() + msl(char(N % 10 + '0'));  
4436 -}  
4437 -  
4438 -template <class CharT, std::intmax_t N, std::intmax_t D>  
4439 -CONSTCD14  
4440 -inline  
4441 -std::enable_if_t  
4442 -<  
4443 - std::ratio<N, D>::type::den != 1,  
4444 - string_literal<CharT, to_string_len(std::ratio<N, D>::type::num) +  
4445 - to_string_len(std::ratio<N, D>::type::den) + 4>  
4446 ->  
4447 -msl(std::ratio<N, D>) NOEXCEPT  
4448 -{  
4449 - using R = typename std::ratio<N, D>::type;  
4450 - return msl(CharT{'['}) + msl<R::num>() + msl(CharT{'/'}) +  
4451 - msl<R::den>() + msl(CharT{']'});  
4452 -}  
4453 -  
4454 -template <class CharT, std::intmax_t N, std::intmax_t D>  
4455 -CONSTCD14  
4456 -inline  
4457 -std::enable_if_t  
4458 -<  
4459 - std::ratio<N, D>::type::den == 1,  
4460 - string_literal<CharT, to_string_len(std::ratio<N, D>::type::num) + 3>  
4461 ->  
4462 -msl(std::ratio<N, D>) NOEXCEPT  
4463 -{  
4464 - using R = typename std::ratio<N, D>::type;  
4465 - return msl(CharT{'['}) + msl<R::num>() + msl(CharT{']'});  
4466 -}  
4467 -  
4468 -  
4469 -#else // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411)  
4470 -  
4471 -inline  
4472 -std::string  
4473 -to_string(std::uint64_t x)  
4474 -{  
4475 - return std::to_string(x);  
4476 -}  
4477 -  
4478 -template <class CharT>  
4479 -inline  
4480 -std::basic_string<CharT>  
4481 -to_string(std::uint64_t x)  
4482 -{  
4483 - auto y = std::to_string(x);  
4484 - return std::basic_string<CharT>(y.begin(), y.end());  
4485 -}  
4486 -  
4487 -template <class CharT, std::intmax_t N, std::intmax_t D>  
4488 -inline  
4489 -typename std::enable_if  
4490 -<  
4491 - std::ratio<N, D>::type::den != 1,  
4492 - std::basic_string<CharT>  
4493 ->::type  
4494 -msl(std::ratio<N, D>)  
4495 -{  
4496 - using R = typename std::ratio<N, D>::type;  
4497 - return std::basic_string<CharT>(1, '[') + to_string<CharT>(R::num) + CharT{'/'} +  
4498 - to_string<CharT>(R::den) + CharT{']'};  
4499 -}  
4500 -  
4501 -template <class CharT, std::intmax_t N, std::intmax_t D>  
4502 -inline  
4503 -typename std::enable_if  
4504 -<  
4505 - std::ratio<N, D>::type::den == 1,  
4506 - std::basic_string<CharT>  
4507 ->::type  
4508 -msl(std::ratio<N, D>)  
4509 -{  
4510 - using R = typename std::ratio<N, D>::type;  
4511 - return std::basic_string<CharT>(1, '[') + to_string<CharT>(R::num) + CharT{']'};  
4512 -}  
4513 -  
4514 -#endif // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411)  
4515 -  
4516 -template <class CharT>  
4517 -CONSTCD11  
4518 -inline  
4519 -string_literal<CharT, 2>  
4520 -msl(std::atto) NOEXCEPT  
4521 -{  
4522 - return string_literal<CharT, 2>{'a'};  
4523 -}  
4524 -  
4525 -template <class CharT>  
4526 -CONSTCD11  
4527 -inline  
4528 -string_literal<CharT, 2>  
4529 -msl(std::femto) NOEXCEPT  
4530 -{  
4531 - return string_literal<CharT, 2>{'f'};  
4532 -}  
4533 -  
4534 -template <class CharT>  
4535 -CONSTCD11  
4536 -inline  
4537 -string_literal<CharT, 2>  
4538 -msl(std::pico) NOEXCEPT  
4539 -{  
4540 - return string_literal<CharT, 2>{'p'};  
4541 -}  
4542 -  
4543 -template <class CharT>  
4544 -CONSTCD11  
4545 -inline  
4546 -string_literal<CharT, 2>  
4547 -msl(std::nano) NOEXCEPT  
4548 -{  
4549 - return string_literal<CharT, 2>{'n'};  
4550 -}  
4551 -  
4552 -template <class CharT>  
4553 -CONSTCD11  
4554 -inline  
4555 -typename std::enable_if  
4556 -<  
4557 - std::is_same<CharT, char>::value,  
4558 - string_literal<char, 3>  
4559 ->::type  
4560 -msl(std::micro) NOEXCEPT  
4561 -{  
4562 - return string_literal<char, 3>{'\xC2', '\xB5'};  
4563 -}  
4564 -  
4565 -template <class CharT>  
4566 -CONSTCD11  
4567 -inline  
4568 -typename std::enable_if  
4569 -<  
4570 - !std::is_same<CharT, char>::value,  
4571 - string_literal<CharT, 2>  
4572 ->::type  
4573 -msl(std::micro) NOEXCEPT  
4574 -{  
4575 - return string_literal<CharT, 2>{CharT{static_cast<unsigned char>('\xB5')}};  
4576 -}  
4577 -  
4578 -template <class CharT>  
4579 -CONSTCD11  
4580 -inline  
4581 -string_literal<CharT, 2>  
4582 -msl(std::milli) NOEXCEPT  
4583 -{  
4584 - return string_literal<CharT, 2>{'m'};  
4585 -}  
4586 -  
4587 -template <class CharT>  
4588 -CONSTCD11  
4589 -inline  
4590 -string_literal<CharT, 2>  
4591 -msl(std::centi) NOEXCEPT  
4592 -{  
4593 - return string_literal<CharT, 2>{'c'};  
4594 -}  
4595 -  
4596 -template <class CharT>  
4597 -CONSTCD11  
4598 -inline  
4599 -string_literal<CharT, 3>  
4600 -msl(std::deca) NOEXCEPT  
4601 -{  
4602 - return string_literal<CharT, 3>{'d', 'a'};  
4603 -}  
4604 -  
4605 -template <class CharT>  
4606 -CONSTCD11  
4607 -inline  
4608 -string_literal<CharT, 2>  
4609 -msl(std::deci) NOEXCEPT  
4610 -{  
4611 - return string_literal<CharT, 2>{'d'};  
4612 -}  
4613 -  
4614 -template <class CharT>  
4615 -CONSTCD11  
4616 -inline  
4617 -string_literal<CharT, 2>  
4618 -msl(std::hecto) NOEXCEPT  
4619 -{  
4620 - return string_literal<CharT, 2>{'h'};  
4621 -}  
4622 -  
4623 -template <class CharT>  
4624 -CONSTCD11  
4625 -inline  
4626 -string_literal<CharT, 2>  
4627 -msl(std::kilo) NOEXCEPT  
4628 -{  
4629 - return string_literal<CharT, 2>{'k'};  
4630 -}  
4631 -  
4632 -template <class CharT>  
4633 -CONSTCD11  
4634 -inline  
4635 -string_literal<CharT, 2>  
4636 -msl(std::mega) NOEXCEPT  
4637 -{  
4638 - return string_literal<CharT, 2>{'M'};  
4639 -}  
4640 -  
4641 -template <class CharT>  
4642 -CONSTCD11  
4643 -inline  
4644 -string_literal<CharT, 2>  
4645 -msl(std::giga) NOEXCEPT  
4646 -{  
4647 - return string_literal<CharT, 2>{'G'};  
4648 -}  
4649 -  
4650 -template <class CharT>  
4651 -CONSTCD11  
4652 -inline  
4653 -string_literal<CharT, 2>  
4654 -msl(std::tera) NOEXCEPT  
4655 -{  
4656 - return string_literal<CharT, 2>{'T'};  
4657 -}  
4658 -  
4659 -template <class CharT>  
4660 -CONSTCD11  
4661 -inline  
4662 -string_literal<CharT, 2>  
4663 -msl(std::peta) NOEXCEPT  
4664 -{  
4665 - return string_literal<CharT, 2>{'P'};  
4666 -}  
4667 -  
4668 -template <class CharT>  
4669 -CONSTCD11  
4670 -inline  
4671 -string_literal<CharT, 2>  
4672 -msl(std::exa) NOEXCEPT  
4673 -{  
4674 - return string_literal<CharT, 2>{'E'};  
4675 -}  
4676 -  
4677 -template <class CharT, class Period>  
4678 -CONSTCD11  
4679 -inline  
4680 -auto  
4681 -get_units(Period p)  
4682 - -> decltype(msl<CharT>(p) + string_literal<CharT, 2>{'s'})  
4683 -{  
4684 - return msl<CharT>(p) + string_literal<CharT, 2>{'s'};  
4685 -}  
4686 -  
4687 -template <class CharT>  
4688 -CONSTCD11  
4689 -inline  
4690 -string_literal<CharT, 2>  
4691 -get_units(std::ratio<1>)  
4692 -{  
4693 - return string_literal<CharT, 2>{'s'};  
4694 -}  
4695 -  
4696 -template <class CharT>  
4697 -CONSTCD11  
4698 -inline  
4699 -string_literal<CharT, 2>  
4700 -get_units(std::ratio<3600>)  
4701 -{  
4702 - return string_literal<CharT, 2>{'h'};  
4703 -}  
4704 -  
4705 -template <class CharT>  
4706 -CONSTCD11  
4707 -inline  
4708 -string_literal<CharT, 4>  
4709 -get_units(std::ratio<60>)  
4710 -{  
4711 - return string_literal<CharT, 4>{'m', 'i', 'n'};  
4712 -}  
4713 -  
4714 -template <class CharT>  
4715 -CONSTCD11  
4716 -inline  
4717 -string_literal<CharT, 2>  
4718 -get_units(std::ratio<86400>)  
4719 -{  
4720 - return string_literal<CharT, 2>{'d'};  
4721 -}  
4722 -  
4723 -template <class CharT, class Traits = std::char_traits<CharT>>  
4724 -struct make_string;  
4725 -  
4726 -template <>  
4727 -struct make_string<char>  
4728 -{  
4729 - template <class Rep>  
4730 - static  
4731 - std::string  
4732 - from(Rep n)  
4733 - {  
4734 - return std::to_string(n);  
4735 - }  
4736 -};  
4737 -  
4738 -template <class Traits>  
4739 -struct make_string<char, Traits>  
4740 -{  
4741 - template <class Rep>  
4742 - static  
4743 - std::basic_string<char, Traits>  
4744 - from(Rep n)  
4745 - {  
4746 - auto s = std::to_string(n);  
4747 - return std::basic_string<char, Traits>(s.begin(), s.end());  
4748 - }  
4749 -};  
4750 -  
4751 -template <>  
4752 -struct make_string<wchar_t>  
4753 -{  
4754 - template <class Rep>  
4755 - static  
4756 - std::wstring  
4757 - from(Rep n)  
4758 - {  
4759 - return std::to_wstring(n);  
4760 - }  
4761 -};  
4762 -  
4763 -template <class Traits>  
4764 -struct make_string<wchar_t, Traits>  
4765 -{  
4766 - template <class Rep>  
4767 - static  
4768 - std::basic_string<wchar_t, Traits>  
4769 - from(Rep n)  
4770 - {  
4771 - auto s = std::to_wstring(n);  
4772 - return std::basic_string<wchar_t, Traits>(s.begin(), s.end());  
4773 - }  
4774 -};  
4775 -  
4776 -} // namespace detail  
4777 -  
4778 -// to_stream  
4779 -  
4780 -CONSTDATA year nanyear{-32768};  
4781 -  
4782 -template <class Duration>  
4783 -struct fields  
4784 -{  
4785 - year_month_day ymd{nanyear/0/0};  
4786 - weekday wd{8u};  
4787 - hh_mm_ss<Duration> tod{};  
4788 - bool has_tod = false;  
4789 -  
4790 -#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ <= 409)  
4791 - fields() : ymd{nanyear/0/0}, wd{8u}, tod{}, has_tod{false} {}  
4792 -#else  
4793 - fields() = default;  
4794 -#endif  
4795 -  
4796 - fields(year_month_day ymd_) : ymd(ymd_) {}  
4797 - fields(weekday wd_) : wd(wd_) {}  
4798 - fields(hh_mm_ss<Duration> tod_) : tod(tod_), has_tod(true) {}  
4799 -  
4800 - fields(year_month_day ymd_, weekday wd_) : ymd(ymd_), wd(wd_) {}  
4801 - fields(year_month_day ymd_, hh_mm_ss<Duration> tod_) : ymd(ymd_), tod(tod_),  
4802 - has_tod(true) {}  
4803 -  
4804 - fields(weekday wd_, hh_mm_ss<Duration> tod_) : wd(wd_), tod(tod_), has_tod(true) {}  
4805 -  
4806 - fields(year_month_day ymd_, weekday wd_, hh_mm_ss<Duration> tod_)  
4807 - : ymd(ymd_)  
4808 - , wd(wd_)  
4809 - , tod(tod_)  
4810 - , has_tod(true)  
4811 - {}  
4812 -};  
4813 -  
4814 -namespace detail  
4815 -{  
4816 -  
4817 -template <class CharT, class Traits, class Duration>  
4818 -unsigned  
4819 -extract_weekday(std::basic_ostream<CharT, Traits>& os, const fields<Duration>& fds)  
4820 -{  
4821 - if (!fds.ymd.ok() && !fds.wd.ok())  
4822 - {  
4823 - // fds does not contain a valid weekday  
4824 - os.setstate(std::ios::failbit);  
4825 - return 8;  
4826 - }  
4827 - weekday wd;  
4828 - if (fds.ymd.ok())  
4829 - {  
4830 - wd = weekday{sys_days(fds.ymd)};  
4831 - if (fds.wd.ok() && wd != fds.wd)  
4832 - {  
4833 - // fds.ymd and fds.wd are inconsistent  
4834 - os.setstate(std::ios::failbit);  
4835 - return 8;  
4836 - }  
4837 - }  
4838 - else  
4839 - wd = fds.wd;  
4840 - return static_cast<unsigned>((wd - Sunday).count());  
4841 -}  
4842 -  
4843 -template <class CharT, class Traits, class Duration>  
4844 -unsigned  
4845 -extract_month(std::basic_ostream<CharT, Traits>& os, const fields<Duration>& fds)  
4846 -{  
4847 - if (!fds.ymd.month().ok())  
4848 - {  
4849 - // fds does not contain a valid month  
4850 - os.setstate(std::ios::failbit);  
4851 - return 0;  
4852 - }  
4853 - return static_cast<unsigned>(fds.ymd.month());  
4854 -}  
4855 -  
4856 -} // namespace detail  
4857 -  
4858 -#if ONLY_C_LOCALE  
4859 -  
4860 -namespace detail  
4861 -{  
4862 -  
4863 -inline  
4864 -std::pair<const std::string*, const std::string*>  
4865 -weekday_names()  
4866 -{  
4867 - static const std::string nm[] =  
4868 - {  
4869 - "Sunday",  
4870 - "Monday",  
4871 - "Tuesday",  
4872 - "Wednesday",  
4873 - "Thursday",  
4874 - "Friday",  
4875 - "Saturday",  
4876 - "Sun",  
4877 - "Mon",  
4878 - "Tue",  
4879 - "Wed",  
4880 - "Thu",  
4881 - "Fri",  
4882 - "Sat"  
4883 - };  
4884 - return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0]));  
4885 -}  
4886 -  
4887 -inline  
4888 -std::pair<const std::string*, const std::string*>  
4889 -month_names()  
4890 -{  
4891 - static const std::string nm[] =  
4892 - {  
4893 - "January",  
4894 - "February",  
4895 - "March",  
4896 - "April",  
4897 - "May",  
4898 - "June",  
4899 - "July",  
4900 - "August",  
4901 - "September",  
4902 - "October",  
4903 - "November",  
4904 - "December",  
4905 - "Jan",  
4906 - "Feb",  
4907 - "Mar",  
4908 - "Apr",  
4909 - "May",  
4910 - "Jun",  
4911 - "Jul",  
4912 - "Aug",  
4913 - "Sep",  
4914 - "Oct",  
4915 - "Nov",  
4916 - "Dec"  
4917 - };  
4918 - return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0]));  
4919 -}  
4920 -  
4921 -inline  
4922 -std::pair<const std::string*, const std::string*>  
4923 -ampm_names()  
4924 -{  
4925 - static const std::string nm[] =  
4926 - {  
4927 - "AM",  
4928 - "PM"  
4929 - };  
4930 - return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0]));  
4931 -}  
4932 -  
4933 -template <class CharT, class Traits, class FwdIter>  
4934 -FwdIter  
4935 -scan_keyword(std::basic_istream<CharT, Traits>& is, FwdIter kb, FwdIter ke)  
4936 -{  
4937 - size_t nkw = static_cast<size_t>(std::distance(kb, ke));  
4938 - const unsigned char doesnt_match = '\0';  
4939 - const unsigned char might_match = '\1';  
4940 - const unsigned char does_match = '\2';  
4941 - unsigned char statbuf[100];  
4942 - unsigned char* status = statbuf;  
4943 - std::unique_ptr<unsigned char, void(*)(void*)> stat_hold(0, free);  
4944 - if (nkw > sizeof(statbuf))  
4945 - {  
4946 - status = (unsigned char*)std::malloc(nkw);  
4947 - if (status == nullptr)  
4948 - throw std::bad_alloc();  
4949 - stat_hold.reset(status);  
4950 - }  
4951 - size_t n_might_match = nkw; // At this point, any keyword might match  
4952 - size_t n_does_match = 0; // but none of them definitely do  
4953 - // Initialize all statuses to might_match, except for "" keywords are does_match  
4954 - unsigned char* st = status;  
4955 - for (auto ky = kb; ky != ke; ++ky, ++st)  
4956 - {  
4957 - if (!ky->empty())  
4958 - *st = might_match;  
4959 - else  
4960 - {  
4961 - *st = does_match;  
4962 - --n_might_match;  
4963 - ++n_does_match;  
4964 - }  
4965 - }  
4966 - // While there might be a match, test keywords against the next CharT  
4967 - for (size_t indx = 0; is && n_might_match > 0; ++indx)  
4968 - {  
4969 - // Peek at the next CharT but don't consume it  
4970 - auto ic = is.peek();  
4971 - if (ic == EOF)  
4972 - {  
4973 - is.setstate(std::ios::eofbit);  
4974 - break;  
4975 - }  
4976 - auto c = static_cast<char>(toupper(static_cast<unsigned char>(ic)));  
4977 - bool consume = false;  
4978 - // For each keyword which might match, see if the indx character is c  
4979 - // If a match if found, consume c  
4980 - // If a match is found, and that is the last character in the keyword,  
4981 - // then that keyword matches.  
4982 - // If the keyword doesn't match this character, then change the keyword  
4983 - // to doesn't match  
4984 - st = status;  
4985 - for (auto ky = kb; ky != ke; ++ky, ++st)  
4986 - {  
4987 - if (*st == might_match)  
4988 - {  
4989 - if (c == static_cast<char>(toupper(static_cast<unsigned char>((*ky)[indx]))))  
4990 - {  
4991 - consume = true;  
4992 - if (ky->size() == indx+1)  
4993 - {  
4994 - *st = does_match;  
4995 - --n_might_match;  
4996 - ++n_does_match;  
4997 - }  
4998 - }  
4999 - else  
5000 - {  
5001 - *st = doesnt_match;  
5002 - --n_might_match;  
5003 - }  
5004 - }  
5005 - }  
5006 - // consume if we matched a character  
5007 - if (consume)  
5008 - {  
5009 - (void)is.get();  
5010 - // If we consumed a character and there might be a matched keyword that  
5011 - // was marked matched on a previous iteration, then such keywords  
5012 - // are now marked as not matching.  
5013 - if (n_might_match + n_does_match > 1)  
5014 - {  
5015 - st = status;  
5016 - for (auto ky = kb; ky != ke; ++ky, ++st)  
5017 - {  
5018 - if (*st == does_match && ky->size() != indx+1)  
5019 - {  
5020 - *st = doesnt_match;  
5021 - --n_does_match;  
5022 - }  
5023 - }  
5024 - }  
5025 - }  
5026 - }  
5027 - // We've exited the loop because we hit eof and/or we have no more "might matches".  
5028 - // Return the first matching result  
5029 - for (st = status; kb != ke; ++kb, ++st)  
5030 - if (*st == does_match)  
5031 - break;  
5032 - if (kb == ke)  
5033 - is.setstate(std::ios::failbit);  
5034 - return kb;  
5035 -}  
5036 -  
5037 -} // namespace detail  
5038 -  
5039 -#endif // ONLY_C_LOCALE  
5040 -  
5041 -template <class CharT, class Traits, class Duration>  
5042 -std::basic_ostream<CharT, Traits>&  
5043 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,  
5044 - const fields<Duration>& fds, const std::string* abbrev,  
5045 - const std::chrono::seconds* offset_sec)  
5046 -{  
5047 -#if ONLY_C_LOCALE  
5048 - using detail::weekday_names;  
5049 - using detail::month_names;  
5050 - using detail::ampm_names;  
5051 -#endif  
5052 - using detail::save_ostream;  
5053 - using detail::get_units;  
5054 - using detail::extract_weekday;  
5055 - using detail::extract_month;  
5056 - using std::ios;  
5057 - using std::chrono::duration_cast;  
5058 - using std::chrono::seconds;  
5059 - using std::chrono::minutes;  
5060 - using std::chrono::hours;  
5061 - date::detail::save_ostream<CharT, Traits> ss(os);  
5062 - os.fill(' ');  
5063 - os.flags(std::ios::skipws | std::ios::dec);  
5064 - os.width(0);  
5065 - tm tm{};  
5066 - bool insert_negative = fds.has_tod && fds.tod.to_duration() < Duration::zero();  
5067 -#if !ONLY_C_LOCALE  
5068 - auto& facet = std::use_facet<std::time_put<CharT>>(os.getloc());  
5069 -#endif  
5070 - const CharT* command = nullptr;  
5071 - CharT modified = CharT{};  
5072 - for (; *fmt; ++fmt)  
5073 - {  
5074 - switch (*fmt)  
5075 - {  
5076 - case 'a':  
5077 - case 'A':  
5078 - if (command)  
5079 - {  
5080 - if (modified == CharT{})  
5081 - {  
5082 - tm.tm_wday = static_cast<int>(extract_weekday(os, fds));  
5083 - if (os.fail())  
5084 - return os;  
5085 -#if !ONLY_C_LOCALE  
5086 - const CharT f[] = {'%', *fmt};  
5087 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5088 -#else // ONLY_C_LOCALE  
5089 - os << weekday_names().first[tm.tm_wday+7*(*fmt == 'a')];  
5090 -#endif // ONLY_C_LOCALE  
5091 - }  
5092 - else  
5093 - {  
5094 - os << CharT{'%'} << modified << *fmt;  
5095 - modified = CharT{};  
5096 - }  
5097 - command = nullptr;  
5098 - }  
5099 - else  
5100 - os << *fmt;  
5101 - break;  
5102 - case 'b':  
5103 - case 'B':  
5104 - case 'h':  
5105 - if (command)  
5106 - {  
5107 - if (modified == CharT{})  
5108 - {  
5109 - tm.tm_mon = static_cast<int>(extract_month(os, fds)) - 1;  
5110 -#if !ONLY_C_LOCALE  
5111 - const CharT f[] = {'%', *fmt};  
5112 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5113 -#else // ONLY_C_LOCALE  
5114 - os << month_names().first[tm.tm_mon+12*(*fmt != 'B')];  
5115 -#endif // ONLY_C_LOCALE  
5116 - }  
5117 - else  
5118 - {  
5119 - os << CharT{'%'} << modified << *fmt;  
5120 - modified = CharT{};  
5121 - }  
5122 - command = nullptr;  
5123 - }  
5124 - else  
5125 - os << *fmt;  
5126 - break;  
5127 - case 'c':  
5128 - case 'x':  
5129 - if (command)  
5130 - {  
5131 - if (modified == CharT{'O'})  
5132 - os << CharT{'%'} << modified << *fmt;  
5133 - else  
5134 - {  
5135 - if (!fds.ymd.ok())  
5136 - os.setstate(std::ios::failbit);  
5137 - if (*fmt == 'c' && !fds.has_tod)  
5138 - os.setstate(std::ios::failbit);  
5139 -#if !ONLY_C_LOCALE  
5140 - tm = std::tm{};  
5141 - auto const& ymd = fds.ymd;  
5142 - auto ld = local_days(ymd);  
5143 - if (*fmt == 'c')  
5144 - {  
5145 - tm.tm_sec = static_cast<int>(fds.tod.seconds().count());  
5146 - tm.tm_min = static_cast<int>(fds.tod.minutes().count());  
5147 - tm.tm_hour = static_cast<int>(fds.tod.hours().count());  
5148 - }  
5149 - tm.tm_mday = static_cast<int>(static_cast<unsigned>(ymd.day()));  
5150 - tm.tm_mon = static_cast<int>(extract_month(os, fds) - 1);  
5151 - tm.tm_year = static_cast<int>(ymd.year()) - 1900;  
5152 - tm.tm_wday = static_cast<int>(extract_weekday(os, fds));  
5153 - if (os.fail())  
5154 - return os;  
5155 - tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());  
5156 - CharT f[3] = {'%'};  
5157 - auto fe = std::begin(f) + 1;  
5158 - if (modified == CharT{'E'})  
5159 - *fe++ = modified;  
5160 - *fe++ = *fmt;  
5161 - facet.put(os, os, os.fill(), &tm, std::begin(f), fe);  
5162 -#else // ONLY_C_LOCALE  
5163 - if (*fmt == 'c')  
5164 - {  
5165 - auto wd = static_cast<int>(extract_weekday(os, fds));  
5166 - os << weekday_names().first[static_cast<unsigned>(wd)+7]  
5167 - << ' ';  
5168 - os << month_names().first[extract_month(os, fds)-1+12] << ' ';  
5169 - auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day()));  
5170 - if (d < 10)  
5171 - os << ' ';  
5172 - os << d << ' '  
5173 - << make_time(duration_cast<seconds>(fds.tod.to_duration()))  
5174 - << ' ' << fds.ymd.year();  
5175 -  
5176 - }  
5177 - else // *fmt == 'x'  
5178 - {  
5179 - auto const& ymd = fds.ymd;  
5180 - save_ostream<CharT, Traits> _(os);  
5181 - os.fill('0');  
5182 - os.flags(std::ios::dec | std::ios::right);  
5183 - os.width(2);  
5184 - os << static_cast<unsigned>(ymd.month()) << CharT{'/'};  
5185 - os.width(2);  
5186 - os << static_cast<unsigned>(ymd.day()) << CharT{'/'};  
5187 - os.width(2);  
5188 - os << static_cast<int>(ymd.year()) % 100;  
5189 - }  
5190 -#endif // ONLY_C_LOCALE  
5191 - }  
5192 - command = nullptr;  
5193 - modified = CharT{};  
5194 - }  
5195 - else  
5196 - os << *fmt;  
5197 - break;  
5198 - case 'C':  
5199 - if (command)  
5200 - {  
5201 - if (modified == CharT{'O'})  
5202 - os << CharT{'%'} << modified << *fmt;  
5203 - else  
5204 - {  
5205 - if (!fds.ymd.year().ok())  
5206 - os.setstate(std::ios::failbit);  
5207 - auto y = static_cast<int>(fds.ymd.year());  
5208 -#if !ONLY_C_LOCALE  
5209 - if (modified == CharT{})  
5210 -#endif  
5211 - {  
5212 - save_ostream<CharT, Traits> _(os);  
5213 - os.fill('0');  
5214 - os.flags(std::ios::dec | std::ios::right);  
5215 - if (y >= 0)  
5216 - {  
5217 - os.width(2);  
5218 - os << y/100;  
5219 - }  
5220 - else  
5221 - {  
5222 - os << CharT{'-'};  
5223 - os.width(2);  
5224 - os << -(y-99)/100;  
5225 - }  
5226 - }  
5227 -#if !ONLY_C_LOCALE  
5228 - else if (modified == CharT{'E'})  
5229 - {  
5230 - tm.tm_year = y - 1900;  
5231 - CharT f[3] = {'%', 'E', 'C'};  
5232 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5233 - }  
5234 -#endif  
5235 - }  
5236 - command = nullptr;  
5237 - modified = CharT{};  
5238 - }  
5239 - else  
5240 - os << *fmt;  
5241 - break;  
5242 - case 'd':  
5243 - case 'e':  
5244 - if (command)  
5245 - {  
5246 - if (modified == CharT{'E'})  
5247 - os << CharT{'%'} << modified << *fmt;  
5248 - else  
5249 - {  
5250 - if (!fds.ymd.day().ok())  
5251 - os.setstate(std::ios::failbit);  
5252 - auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day()));  
5253 -#if !ONLY_C_LOCALE  
5254 - if (modified == CharT{})  
5255 -#endif  
5256 - {  
5257 - save_ostream<CharT, Traits> _(os);  
5258 - if (*fmt == CharT{'d'})  
5259 - os.fill('0');  
5260 - else  
5261 - os.fill(' ');  
5262 - os.flags(std::ios::dec | std::ios::right);  
5263 - os.width(2);  
5264 - os << d;  
5265 - }  
5266 -#if !ONLY_C_LOCALE  
5267 - else if (modified == CharT{'O'})  
5268 - {  
5269 - tm.tm_mday = d;  
5270 - CharT f[3] = {'%', 'O', *fmt};  
5271 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5272 - }  
5273 -#endif  
5274 - }  
5275 - command = nullptr;  
5276 - modified = CharT{};  
5277 - }  
5278 - else  
5279 - os << *fmt;  
5280 - break;  
5281 - case 'D':  
5282 - if (command)  
5283 - {  
5284 - if (modified == CharT{})  
5285 - {  
5286 - if (!fds.ymd.ok())  
5287 - os.setstate(std::ios::failbit);  
5288 - auto const& ymd = fds.ymd;  
5289 - save_ostream<CharT, Traits> _(os);  
5290 - os.fill('0');  
5291 - os.flags(std::ios::dec | std::ios::right);  
5292 - os.width(2);  
5293 - os << static_cast<unsigned>(ymd.month()) << CharT{'/'};  
5294 - os.width(2);  
5295 - os << static_cast<unsigned>(ymd.day()) << CharT{'/'};  
5296 - os.width(2);  
5297 - os << static_cast<int>(ymd.year()) % 100;  
5298 - }  
5299 - else  
5300 - {  
5301 - os << CharT{'%'} << modified << *fmt;  
5302 - modified = CharT{};  
5303 - }  
5304 - command = nullptr;  
5305 - }  
5306 - else  
5307 - os << *fmt;  
5308 - break;  
5309 - case 'F':  
5310 - if (command)  
5311 - {  
5312 - if (modified == CharT{})  
5313 - {  
5314 - if (!fds.ymd.ok())  
5315 - os.setstate(std::ios::failbit);  
5316 - auto const& ymd = fds.ymd;  
5317 - save_ostream<CharT, Traits> _(os);  
5318 - os.imbue(std::locale::classic());  
5319 - os.fill('0');  
5320 - os.flags(std::ios::dec | std::ios::right);  
5321 - os.width(4);  
5322 - os << static_cast<int>(ymd.year()) << CharT{'-'};  
5323 - os.width(2);  
5324 - os << static_cast<unsigned>(ymd.month()) << CharT{'-'};  
5325 - os.width(2);  
5326 - os << static_cast<unsigned>(ymd.day());  
5327 - }  
5328 - else  
5329 - {  
5330 - os << CharT{'%'} << modified << *fmt;  
5331 - modified = CharT{};  
5332 - }  
5333 - command = nullptr;  
5334 - }  
5335 - else  
5336 - os << *fmt;  
5337 - break;  
5338 - case 'g':  
5339 - case 'G':  
5340 - if (command)  
5341 - {  
5342 - if (modified == CharT{})  
5343 - {  
5344 - if (!fds.ymd.ok())  
5345 - os.setstate(std::ios::failbit);  
5346 - auto ld = local_days(fds.ymd);  
5347 - auto y = year_month_day{ld + days{3}}.year();  
5348 - auto start = local_days((y-years{1})/December/Thursday[last]) +  
5349 - (Monday-Thursday);  
5350 - if (ld < start)  
5351 - --y;  
5352 - if (*fmt == CharT{'G'})  
5353 - os << y;  
5354 - else  
5355 - {  
5356 - save_ostream<CharT, Traits> _(os);  
5357 - os.fill('0');  
5358 - os.flags(std::ios::dec | std::ios::right);  
5359 - os.width(2);  
5360 - os << std::abs(static_cast<int>(y)) % 100;  
5361 - }  
5362 - }  
5363 - else  
5364 - {  
5365 - os << CharT{'%'} << modified << *fmt;  
5366 - modified = CharT{};  
5367 - }  
5368 - command = nullptr;  
5369 - }  
5370 - else  
5371 - os << *fmt;  
5372 - break;  
5373 - case 'H':  
5374 - case 'I':  
5375 - if (command)  
5376 - {  
5377 - if (modified == CharT{'E'})  
5378 - os << CharT{'%'} << modified << *fmt;  
5379 - else  
5380 - {  
5381 - if (!fds.has_tod)  
5382 - os.setstate(std::ios::failbit);  
5383 - if (insert_negative)  
5384 - {  
5385 - os << '-';  
5386 - insert_negative = false;  
5387 - }  
5388 - auto hms = fds.tod;  
5389 -#if !ONLY_C_LOCALE  
5390 - if (modified == CharT{})  
5391 -#endif  
5392 - {  
5393 - auto h = *fmt == CharT{'I'} ? date::make12(hms.hours()) : hms.hours();  
5394 - if (h < hours{10})  
5395 - os << CharT{'0'};  
5396 - os << h.count();  
5397 - }  
5398 -#if !ONLY_C_LOCALE  
5399 - else if (modified == CharT{'O'})  
5400 - {  
5401 - const CharT f[] = {'%', modified, *fmt};  
5402 - tm.tm_hour = static_cast<int>(hms.hours().count());  
5403 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5404 - }  
5405 -#endif  
5406 - }  
5407 - modified = CharT{};  
5408 - command = nullptr;  
5409 - }  
5410 - else  
5411 - os << *fmt;  
5412 - break;  
5413 - case 'j':  
5414 - if (command)  
5415 - {  
5416 - if (modified == CharT{})  
5417 - {  
5418 - if (fds.ymd.ok() || fds.has_tod)  
5419 - {  
5420 - days doy;  
5421 - if (fds.ymd.ok())  
5422 - {  
5423 - auto ld = local_days(fds.ymd);  
5424 - auto y = fds.ymd.year();  
5425 - doy = ld - local_days(y/January/1) + days{1};  
5426 - }  
5427 - else  
5428 - {  
5429 - doy = duration_cast<days>(fds.tod.to_duration());  
5430 - }  
5431 - save_ostream<CharT, Traits> _(os);  
5432 - os.fill('0');  
5433 - os.flags(std::ios::dec | std::ios::right);  
5434 - os.width(3);  
5435 - os << doy.count();  
5436 - }  
5437 - else  
5438 - {  
5439 - os.setstate(std::ios::failbit);  
5440 - }  
5441 - }  
5442 - else  
5443 - {  
5444 - os << CharT{'%'} << modified << *fmt;  
5445 - modified = CharT{};  
5446 - }  
5447 - command = nullptr;  
5448 - }  
5449 - else  
5450 - os << *fmt;  
5451 - break;  
5452 - case 'm':  
5453 - if (command)  
5454 - {  
5455 - if (modified == CharT{'E'})  
5456 - os << CharT{'%'} << modified << *fmt;  
5457 - else  
5458 - {  
5459 - if (!fds.ymd.month().ok())  
5460 - os.setstate(std::ios::failbit);  
5461 - auto m = static_cast<unsigned>(fds.ymd.month());  
5462 -#if !ONLY_C_LOCALE  
5463 - if (modified == CharT{})  
5464 -#endif  
5465 - {  
5466 - if (m < 10)  
5467 - os << CharT{'0'};  
5468 - os << m;  
5469 - }  
5470 -#if !ONLY_C_LOCALE  
5471 - else if (modified == CharT{'O'})  
5472 - {  
5473 - const CharT f[] = {'%', modified, *fmt};  
5474 - tm.tm_mon = static_cast<int>(m-1);  
5475 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5476 - }  
5477 -#endif  
5478 - }  
5479 - modified = CharT{};  
5480 - command = nullptr;  
5481 - }  
5482 - else  
5483 - os << *fmt;  
5484 - break;  
5485 - case 'M':  
5486 - if (command)  
5487 - {  
5488 - if (modified == CharT{'E'})  
5489 - os << CharT{'%'} << modified << *fmt;  
5490 - else  
5491 - {  
5492 - if (!fds.has_tod)  
5493 - os.setstate(std::ios::failbit);  
5494 - if (insert_negative)  
5495 - {  
5496 - os << '-';  
5497 - insert_negative = false;  
5498 - }  
5499 -#if !ONLY_C_LOCALE  
5500 - if (modified == CharT{})  
5501 -#endif  
5502 - {  
5503 - if (fds.tod.minutes() < minutes{10})  
5504 - os << CharT{'0'};  
5505 - os << fds.tod.minutes().count();  
5506 - }  
5507 -#if !ONLY_C_LOCALE  
5508 - else if (modified == CharT{'O'})  
5509 - {  
5510 - const CharT f[] = {'%', modified, *fmt};  
5511 - tm.tm_min = static_cast<int>(fds.tod.minutes().count());  
5512 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5513 - }  
5514 -#endif  
5515 - }  
5516 - modified = CharT{};  
5517 - command = nullptr;  
5518 - }  
5519 - else  
5520 - os << *fmt;  
5521 - break;  
5522 - case 'n':  
5523 - if (command)  
5524 - {  
5525 - if (modified == CharT{})  
5526 - os << CharT{'\n'};  
5527 - else  
5528 - {  
5529 - os << CharT{'%'} << modified << *fmt;  
5530 - modified = CharT{};  
5531 - }  
5532 - command = nullptr;  
5533 - }  
5534 - else  
5535 - os << *fmt;  
5536 - break;  
5537 - case 'p':  
5538 - if (command)  
5539 - {  
5540 - if (modified == CharT{})  
5541 - {  
5542 - if (!fds.has_tod)  
5543 - os.setstate(std::ios::failbit);  
5544 -#if !ONLY_C_LOCALE  
5545 - const CharT f[] = {'%', *fmt};  
5546 - tm.tm_hour = static_cast<int>(fds.tod.hours().count());  
5547 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5548 -#else  
5549 - if (date::is_am(fds.tod.hours()))  
5550 - os << ampm_names().first[0];  
5551 - else  
5552 - os << ampm_names().first[1];  
5553 -#endif  
5554 - }  
5555 - else  
5556 - {  
5557 - os << CharT{'%'} << modified << *fmt;  
5558 - }  
5559 - modified = CharT{};  
5560 - command = nullptr;  
5561 - }  
5562 - else  
5563 - os << *fmt;  
5564 - break;  
5565 - case 'Q':  
5566 - case 'q':  
5567 - if (command)  
5568 - {  
5569 - if (modified == CharT{})  
5570 - {  
5571 - if (!fds.has_tod)  
5572 - os.setstate(std::ios::failbit);  
5573 - auto d = fds.tod.to_duration();  
5574 - if (*fmt == 'q')  
5575 - os << get_units<CharT>(typename decltype(d)::period::type{});  
5576 - else  
5577 - os << d.count();  
5578 - }  
5579 - else  
5580 - {  
5581 - os << CharT{'%'} << modified << *fmt;  
5582 - }  
5583 - modified = CharT{};  
5584 - command = nullptr;  
5585 - }  
5586 - else  
5587 - os << *fmt;  
5588 - break;  
5589 - case 'r':  
5590 - if (command)  
5591 - {  
5592 - if (modified == CharT{})  
5593 - {  
5594 - if (!fds.has_tod)  
5595 - os.setstate(std::ios::failbit);  
5596 -#if !ONLY_C_LOCALE  
5597 - const CharT f[] = {'%', *fmt};  
5598 - tm.tm_hour = static_cast<int>(fds.tod.hours().count());  
5599 - tm.tm_min = static_cast<int>(fds.tod.minutes().count());  
5600 - tm.tm_sec = static_cast<int>(fds.tod.seconds().count());  
5601 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5602 -#else  
5603 - hh_mm_ss<seconds> tod(duration_cast<seconds>(fds.tod.to_duration()));  
5604 - save_ostream<CharT, Traits> _(os);  
5605 - os.fill('0');  
5606 - os.width(2);  
5607 - os << date::make12(tod.hours()).count() << CharT{':'};  
5608 - os.width(2);  
5609 - os << tod.minutes().count() << CharT{':'};  
5610 - os.width(2);  
5611 - os << tod.seconds().count() << CharT{' '};  
5612 - if (date::is_am(tod.hours()))  
5613 - os << ampm_names().first[0];  
5614 - else  
5615 - os << ampm_names().first[1];  
5616 -#endif  
5617 - }  
5618 - else  
5619 - {  
5620 - os << CharT{'%'} << modified << *fmt;  
5621 - }  
5622 - modified = CharT{};  
5623 - command = nullptr;  
5624 - }  
5625 - else  
5626 - os << *fmt;  
5627 - break;  
5628 - case 'R':  
5629 - if (command)  
5630 - {  
5631 - if (modified == CharT{})  
5632 - {  
5633 - if (!fds.has_tod)  
5634 - os.setstate(std::ios::failbit);  
5635 - if (fds.tod.hours() < hours{10})  
5636 - os << CharT{'0'};  
5637 - os << fds.tod.hours().count() << CharT{':'};  
5638 - if (fds.tod.minutes() < minutes{10})  
5639 - os << CharT{'0'};  
5640 - os << fds.tod.minutes().count();  
5641 - }  
5642 - else  
5643 - {  
5644 - os << CharT{'%'} << modified << *fmt;  
5645 - modified = CharT{};  
5646 - }  
5647 - command = nullptr;  
5648 - }  
5649 - else  
5650 - os << *fmt;  
5651 - break;  
5652 - case 'S':  
5653 - if (command)  
5654 - {  
5655 - if (modified == CharT{'E'})  
5656 - os << CharT{'%'} << modified << *fmt;  
5657 - else  
5658 - {  
5659 - if (!fds.has_tod)  
5660 - os.setstate(std::ios::failbit);  
5661 - if (insert_negative)  
5662 - {  
5663 - os << '-';  
5664 - insert_negative = false;  
5665 - }  
5666 -#if !ONLY_C_LOCALE  
5667 - if (modified == CharT{})  
5668 -#endif  
5669 - {  
5670 - os << fds.tod.s_;  
5671 - }  
5672 -#if !ONLY_C_LOCALE  
5673 - else if (modified == CharT{'O'})  
5674 - {  
5675 - const CharT f[] = {'%', modified, *fmt};  
5676 - tm.tm_sec = static_cast<int>(fds.tod.s_.seconds().count());  
5677 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5678 - }  
5679 -#endif  
5680 - }  
5681 - modified = CharT{};  
5682 - command = nullptr;  
5683 - }  
5684 - else  
5685 - os << *fmt;  
5686 - break;  
5687 - case 't':  
5688 - if (command)  
5689 - {  
5690 - if (modified == CharT{})  
5691 - os << CharT{'\t'};  
5692 - else  
5693 - {  
5694 - os << CharT{'%'} << modified << *fmt;  
5695 - modified = CharT{};  
5696 - }  
5697 - command = nullptr;  
5698 - }  
5699 - else  
5700 - os << *fmt;  
5701 - break;  
5702 - case 'T':  
5703 - if (command)  
5704 - {  
5705 - if (modified == CharT{})  
5706 - {  
5707 - if (!fds.has_tod)  
5708 - os.setstate(std::ios::failbit);  
5709 - os << fds.tod;  
5710 - }  
5711 - else  
5712 - {  
5713 - os << CharT{'%'} << modified << *fmt;  
5714 - modified = CharT{};  
5715 - }  
5716 - command = nullptr;  
5717 - }  
5718 - else  
5719 - os << *fmt;  
5720 - break;  
5721 - case 'u':  
5722 - if (command)  
5723 - {  
5724 - if (modified == CharT{'E'})  
5725 - os << CharT{'%'} << modified << *fmt;  
5726 - else  
5727 - {  
5728 - auto wd = extract_weekday(os, fds);  
5729 -#if !ONLY_C_LOCALE  
5730 - if (modified == CharT{})  
5731 -#endif  
5732 - {  
5733 - os << (wd != 0 ? wd : 7u);  
5734 - }  
5735 -#if !ONLY_C_LOCALE  
5736 - else if (modified == CharT{'O'})  
5737 - {  
5738 - const CharT f[] = {'%', modified, *fmt};  
5739 - tm.tm_wday = static_cast<int>(wd);  
5740 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5741 - }  
5742 -#endif  
5743 - }  
5744 - modified = CharT{};  
5745 - command = nullptr;  
5746 - }  
5747 - else  
5748 - os << *fmt;  
5749 - break;  
5750 - case 'U':  
5751 - if (command)  
5752 - {  
5753 - if (modified == CharT{'E'})  
5754 - os << CharT{'%'} << modified << *fmt;  
5755 - else  
5756 - {  
5757 - auto const& ymd = fds.ymd;  
5758 - if (!ymd.ok())  
5759 - os.setstate(std::ios::failbit);  
5760 - auto ld = local_days(ymd);  
5761 -#if !ONLY_C_LOCALE  
5762 - if (modified == CharT{})  
5763 -#endif  
5764 - {  
5765 - auto st = local_days(Sunday[1]/January/ymd.year());  
5766 - if (ld < st)  
5767 - os << CharT{'0'} << CharT{'0'};  
5768 - else  
5769 - {  
5770 - auto wn = duration_cast<weeks>(ld - st).count() + 1;  
5771 - if (wn < 10)  
5772 - os << CharT{'0'};  
5773 - os << wn;  
5774 - }  
5775 - }  
5776 - #if !ONLY_C_LOCALE  
5777 - else if (modified == CharT{'O'})  
5778 - {  
5779 - const CharT f[] = {'%', modified, *fmt};  
5780 - tm.tm_year = static_cast<int>(ymd.year()) - 1900;  
5781 - tm.tm_wday = static_cast<int>(extract_weekday(os, fds));  
5782 - if (os.fail())  
5783 - return os;  
5784 - tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());  
5785 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5786 - }  
5787 -#endif  
5788 - }  
5789 - modified = CharT{};  
5790 - command = nullptr;  
5791 - }  
5792 - else  
5793 - os << *fmt;  
5794 - break;  
5795 - case 'V':  
5796 - if (command)  
5797 - {  
5798 - if (modified == CharT{'E'})  
5799 - os << CharT{'%'} << modified << *fmt;  
5800 - else  
5801 - {  
5802 - if (!fds.ymd.ok())  
5803 - os.setstate(std::ios::failbit);  
5804 - auto ld = local_days(fds.ymd);  
5805 -#if !ONLY_C_LOCALE  
5806 - if (modified == CharT{})  
5807 -#endif  
5808 - {  
5809 - auto y = year_month_day{ld + days{3}}.year();  
5810 - auto st = local_days((y-years{1})/12/Thursday[last]) +  
5811 - (Monday-Thursday);  
5812 - if (ld < st)  
5813 - {  
5814 - --y;  
5815 - st = local_days((y - years{1})/12/Thursday[last]) +  
5816 - (Monday-Thursday);  
5817 - }  
5818 - auto wn = duration_cast<weeks>(ld - st).count() + 1;  
5819 - if (wn < 10)  
5820 - os << CharT{'0'};  
5821 - os << wn;  
5822 - }  
5823 -#if !ONLY_C_LOCALE  
5824 - else if (modified == CharT{'O'})  
5825 - {  
5826 - const CharT f[] = {'%', modified, *fmt};  
5827 - auto const& ymd = fds.ymd;  
5828 - tm.tm_year = static_cast<int>(ymd.year()) - 1900;  
5829 - tm.tm_wday = static_cast<int>(extract_weekday(os, fds));  
5830 - if (os.fail())  
5831 - return os;  
5832 - tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());  
5833 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5834 - }  
5835 -#endif  
5836 - }  
5837 - modified = CharT{};  
5838 - command = nullptr;  
5839 - }  
5840 - else  
5841 - os << *fmt;  
5842 - break;  
5843 - case 'w':  
5844 - if (command)  
5845 - {  
5846 - auto wd = extract_weekday(os, fds);  
5847 - if (os.fail())  
5848 - return os;  
5849 -#if !ONLY_C_LOCALE  
5850 - if (modified == CharT{})  
5851 -#else  
5852 - if (modified != CharT{'E'})  
5853 -#endif  
5854 - {  
5855 - os << wd;  
5856 - }  
5857 -#if !ONLY_C_LOCALE  
5858 - else if (modified == CharT{'O'})  
5859 - {  
5860 - const CharT f[] = {'%', modified, *fmt};  
5861 - tm.tm_wday = static_cast<int>(wd);  
5862 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5863 - }  
5864 -#endif  
5865 - else  
5866 - {  
5867 - os << CharT{'%'} << modified << *fmt;  
5868 - }  
5869 - modified = CharT{};  
5870 - command = nullptr;  
5871 - }  
5872 - else  
5873 - os << *fmt;  
5874 - break;  
5875 - case 'W':  
5876 - if (command)  
5877 - {  
5878 - if (modified == CharT{'E'})  
5879 - os << CharT{'%'} << modified << *fmt;  
5880 - else  
5881 - {  
5882 - auto const& ymd = fds.ymd;  
5883 - if (!ymd.ok())  
5884 - os.setstate(std::ios::failbit);  
5885 - auto ld = local_days(ymd);  
5886 -#if !ONLY_C_LOCALE  
5887 - if (modified == CharT{})  
5888 -#endif  
5889 - {  
5890 - auto st = local_days(Monday[1]/January/ymd.year());  
5891 - if (ld < st)  
5892 - os << CharT{'0'} << CharT{'0'};  
5893 - else  
5894 - {  
5895 - auto wn = duration_cast<weeks>(ld - st).count() + 1;  
5896 - if (wn < 10)  
5897 - os << CharT{'0'};  
5898 - os << wn;  
5899 - }  
5900 - }  
5901 -#if !ONLY_C_LOCALE  
5902 - else if (modified == CharT{'O'})  
5903 - {  
5904 - const CharT f[] = {'%', modified, *fmt};  
5905 - tm.tm_year = static_cast<int>(ymd.year()) - 1900;  
5906 - tm.tm_wday = static_cast<int>(extract_weekday(os, fds));  
5907 - if (os.fail())  
5908 - return os;  
5909 - tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());  
5910 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5911 - }  
5912 -#endif  
5913 - }  
5914 - modified = CharT{};  
5915 - command = nullptr;  
5916 - }  
5917 - else  
5918 - os << *fmt;  
5919 - break;  
5920 - case 'X':  
5921 - if (command)  
5922 - {  
5923 - if (modified == CharT{'O'})  
5924 - os << CharT{'%'} << modified << *fmt;  
5925 - else  
5926 - {  
5927 - if (!fds.has_tod)  
5928 - os.setstate(std::ios::failbit);  
5929 -#if !ONLY_C_LOCALE  
5930 - tm = std::tm{};  
5931 - tm.tm_sec = static_cast<int>(fds.tod.seconds().count());  
5932 - tm.tm_min = static_cast<int>(fds.tod.minutes().count());  
5933 - tm.tm_hour = static_cast<int>(fds.tod.hours().count());  
5934 - CharT f[3] = {'%'};  
5935 - auto fe = std::begin(f) + 1;  
5936 - if (modified == CharT{'E'})  
5937 - *fe++ = modified;  
5938 - *fe++ = *fmt;  
5939 - facet.put(os, os, os.fill(), &tm, std::begin(f), fe);  
5940 -#else  
5941 - os << fds.tod;  
5942 -#endif  
5943 - }  
5944 - command = nullptr;  
5945 - modified = CharT{};  
5946 - }  
5947 - else  
5948 - os << *fmt;  
5949 - break;  
5950 - case 'y':  
5951 - if (command)  
5952 - {  
5953 - if (!fds.ymd.year().ok())  
5954 - os.setstate(std::ios::failbit);  
5955 - auto y = static_cast<int>(fds.ymd.year());  
5956 -#if !ONLY_C_LOCALE  
5957 - if (modified == CharT{})  
5958 - {  
5959 -#endif  
5960 - y = std::abs(y) % 100;  
5961 - if (y < 10)  
5962 - os << CharT{'0'};  
5963 - os << y;  
5964 -#if !ONLY_C_LOCALE  
5965 - }  
5966 - else  
5967 - {  
5968 - const CharT f[] = {'%', modified, *fmt};  
5969 - tm.tm_year = y - 1900;  
5970 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
5971 - }  
5972 -#endif  
5973 - modified = CharT{};  
5974 - command = nullptr;  
5975 - }  
5976 - else  
5977 - os << *fmt;  
5978 - break;  
5979 - case 'Y':  
5980 - if (command)  
5981 - {  
5982 - if (modified == CharT{'O'})  
5983 - os << CharT{'%'} << modified << *fmt;  
5984 - else  
5985 - {  
5986 - if (!fds.ymd.year().ok())  
5987 - os.setstate(std::ios::failbit);  
5988 - auto y = fds.ymd.year();  
5989 -#if !ONLY_C_LOCALE  
5990 - if (modified == CharT{})  
5991 -#endif  
5992 - {  
5993 - save_ostream<CharT, Traits> _(os);  
5994 - os.imbue(std::locale::classic());  
5995 - os << y;  
5996 - }  
5997 -#if !ONLY_C_LOCALE  
5998 - else if (modified == CharT{'E'})  
5999 - {  
6000 - const CharT f[] = {'%', modified, *fmt};  
6001 - tm.tm_year = static_cast<int>(y) - 1900;  
6002 - facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));  
6003 - }  
6004 -#endif  
6005 - }  
6006 - modified = CharT{};  
6007 - command = nullptr;  
6008 - }  
6009 - else  
6010 - os << *fmt;  
6011 - break;  
6012 - case 'z':  
6013 - if (command)  
6014 - {  
6015 - if (offset_sec == nullptr)  
6016 - {  
6017 - // Can not format %z with unknown offset  
6018 - os.setstate(ios::failbit);  
6019 - return os;  
6020 - }  
6021 - auto m = duration_cast<minutes>(*offset_sec);  
6022 - auto neg = m < minutes{0};  
6023 - m = date::abs(m);  
6024 - auto h = duration_cast<hours>(m);  
6025 - m -= h;  
6026 - if (neg)  
6027 - os << CharT{'-'};  
6028 - else  
6029 - os << CharT{'+'};  
6030 - if (h < hours{10})  
6031 - os << CharT{'0'};  
6032 - os << h.count();  
6033 - if (modified != CharT{})  
6034 - os << CharT{':'};  
6035 - if (m < minutes{10})  
6036 - os << CharT{'0'};  
6037 - os << m.count();  
6038 - command = nullptr;  
6039 - modified = CharT{};  
6040 - }  
6041 - else  
6042 - os << *fmt;  
6043 - break;  
6044 - case 'Z':  
6045 - if (command)  
6046 - {  
6047 - if (modified == CharT{})  
6048 - {  
6049 - if (abbrev == nullptr)  
6050 - {  
6051 - // Can not format %Z with unknown time_zone  
6052 - os.setstate(ios::failbit);  
6053 - return os;  
6054 - }  
6055 - for (auto c : *abbrev)  
6056 - os << CharT(c);  
6057 - }  
6058 - else  
6059 - {  
6060 - os << CharT{'%'} << modified << *fmt;  
6061 - modified = CharT{};  
6062 - }  
6063 - command = nullptr;  
6064 - }  
6065 - else  
6066 - os << *fmt;  
6067 - break;  
6068 - case 'E':  
6069 - case 'O':  
6070 - if (command)  
6071 - {  
6072 - if (modified == CharT{})  
6073 - {  
6074 - modified = *fmt;  
6075 - }  
6076 - else  
6077 - {  
6078 - os << CharT{'%'} << modified << *fmt;  
6079 - command = nullptr;  
6080 - modified = CharT{};  
6081 - }  
6082 - }  
6083 - else  
6084 - os << *fmt;  
6085 - break;  
6086 - case '%':  
6087 - if (command)  
6088 - {  
6089 - if (modified == CharT{})  
6090 - {  
6091 - os << CharT{'%'};  
6092 - command = nullptr;  
6093 - }  
6094 - else  
6095 - {  
6096 - os << CharT{'%'} << modified << CharT{'%'};  
6097 - command = nullptr;  
6098 - modified = CharT{};  
6099 - }  
6100 - }  
6101 - else  
6102 - command = fmt;  
6103 - break;  
6104 - default:  
6105 - if (command)  
6106 - {  
6107 - os << CharT{'%'};  
6108 - command = nullptr;  
6109 - }  
6110 - if (modified != CharT{})  
6111 - {  
6112 - os << modified;  
6113 - modified = CharT{};  
6114 - }  
6115 - os << *fmt;  
6116 - break;  
6117 - }  
6118 - }  
6119 - if (command)  
6120 - os << CharT{'%'};  
6121 - if (modified != CharT{})  
6122 - os << modified;  
6123 - return os;  
6124 -}  
6125 -  
6126 -template <class CharT, class Traits>  
6127 -inline  
6128 -std::basic_ostream<CharT, Traits>&  
6129 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const year& y)  
6130 -{  
6131 - using CT = std::chrono::seconds;  
6132 - fields<CT> fds{y/0/0};  
6133 - return to_stream(os, fmt, fds);  
6134 -}  
6135 -  
6136 -template <class CharT, class Traits>  
6137 -inline  
6138 -std::basic_ostream<CharT, Traits>&  
6139 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const month& m)  
6140 -{  
6141 - using CT = std::chrono::seconds;  
6142 - fields<CT> fds{m/0/nanyear};  
6143 - return to_stream(os, fmt, fds);  
6144 -}  
6145 -  
6146 -template <class CharT, class Traits>  
6147 -inline  
6148 -std::basic_ostream<CharT, Traits>&  
6149 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const day& d)  
6150 -{  
6151 - using CT = std::chrono::seconds;  
6152 - fields<CT> fds{d/0/nanyear};  
6153 - return to_stream(os, fmt, fds);  
6154 -}  
6155 -  
6156 -template <class CharT, class Traits>  
6157 -inline  
6158 -std::basic_ostream<CharT, Traits>&  
6159 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const weekday& wd)  
6160 -{  
6161 - using CT = std::chrono::seconds;  
6162 - fields<CT> fds{wd};  
6163 - return to_stream(os, fmt, fds);  
6164 -}  
6165 -  
6166 -template <class CharT, class Traits>  
6167 -inline  
6168 -std::basic_ostream<CharT, Traits>&  
6169 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const year_month& ym)  
6170 -{  
6171 - using CT = std::chrono::seconds;  
6172 - fields<CT> fds{ym/0};  
6173 - return to_stream(os, fmt, fds);  
6174 -}  
6175 -  
6176 -template <class CharT, class Traits>  
6177 -inline  
6178 -std::basic_ostream<CharT, Traits>&  
6179 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const month_day& md)  
6180 -{  
6181 - using CT = std::chrono::seconds;  
6182 - fields<CT> fds{md/nanyear};  
6183 - return to_stream(os, fmt, fds);  
6184 -}  
6185 -  
6186 -template <class CharT, class Traits>  
6187 -inline  
6188 -std::basic_ostream<CharT, Traits>&  
6189 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,  
6190 - const year_month_day& ymd)  
6191 -{  
6192 - using CT = std::chrono::seconds;  
6193 - fields<CT> fds{ymd};  
6194 - return to_stream(os, fmt, fds);  
6195 -}  
6196 -  
6197 -template <class CharT, class Traits, class Rep, class Period>  
6198 -inline  
6199 -std::basic_ostream<CharT, Traits>&  
6200 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,  
6201 - const std::chrono::duration<Rep, Period>& d)  
6202 -{  
6203 - using Duration = std::chrono::duration<Rep, Period>;  
6204 - using CT = typename std::common_type<Duration, std::chrono::seconds>::type;  
6205 - fields<CT> fds{hh_mm_ss<CT>{d}};  
6206 - return to_stream(os, fmt, fds);  
6207 -}  
6208 -  
6209 -template <class CharT, class Traits, class Duration>  
6210 -std::basic_ostream<CharT, Traits>&  
6211 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,  
6212 - const local_time<Duration>& tp, const std::string* abbrev = nullptr,  
6213 - const std::chrono::seconds* offset_sec = nullptr)  
6214 -{  
6215 - using CT = typename std::common_type<Duration, std::chrono::seconds>::type;  
6216 - auto ld = std::chrono::time_point_cast<days>(tp);  
6217 - fields<CT> fds;  
6218 - if (ld <= tp)  
6219 - fds = fields<CT>{year_month_day{ld}, hh_mm_ss<CT>{tp-local_seconds{ld}}};  
6220 - else  
6221 - fds = fields<CT>{year_month_day{ld - days{1}},  
6222 - hh_mm_ss<CT>{days{1} - (local_seconds{ld} - tp)}};  
6223 - return to_stream(os, fmt, fds, abbrev, offset_sec);  
6224 -}  
6225 -  
6226 -template <class CharT, class Traits, class Duration>  
6227 -std::basic_ostream<CharT, Traits>&  
6228 -to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,  
6229 - const sys_time<Duration>& tp)  
6230 -{  
6231 - using std::chrono::seconds;  
6232 - using CT = typename std::common_type<Duration, seconds>::type;  
6233 - const std::string abbrev("UTC");  
6234 - CONSTDATA seconds offset{0};  
6235 - auto sd = std::chrono::time_point_cast<days>(tp);  
6236 - fields<CT> fds;  
6237 - if (sd <= tp)  
6238 - fds = fields<CT>{year_month_day{sd}, hh_mm_ss<CT>{tp-sys_seconds{sd}}};  
6239 - else  
6240 - fds = fields<CT>{year_month_day{sd - days{1}},  
6241 - hh_mm_ss<CT>{days{1} - (sys_seconds{sd} - tp)}};  
6242 - return to_stream(os, fmt, fds, &abbrev, &offset);  
6243 -}  
6244 -  
6245 -// format  
6246 -  
6247 -template <class CharT, class Streamable>  
6248 -auto  
6249 -format(const std::locale& loc, const CharT* fmt, const Streamable& tp)  
6250 - -> decltype(to_stream(std::declval<std::basic_ostream<CharT>&>(), fmt, tp),  
6251 - std::basic_string<CharT>{})  
6252 -{  
6253 - std::basic_ostringstream<CharT> os;  
6254 - os.exceptions(std::ios::failbit | std::ios::badbit);  
6255 - os.imbue(loc);  
6256 - to_stream(os, fmt, tp);  
6257 - return os.str();  
6258 -}  
6259 -  
6260 -template <class CharT, class Streamable>  
6261 -auto  
6262 -format(const CharT* fmt, const Streamable& tp)  
6263 - -> decltype(to_stream(std::declval<std::basic_ostream<CharT>&>(), fmt, tp),  
6264 - std::basic_string<CharT>{})  
6265 -{  
6266 - std::basic_ostringstream<CharT> os;  
6267 - os.exceptions(std::ios::failbit | std::ios::badbit);  
6268 - to_stream(os, fmt, tp);  
6269 - return os.str();  
6270 -}  
6271 -  
6272 -template <class CharT, class Traits, class Alloc, class Streamable>  
6273 -auto  
6274 -format(const std::locale& loc, const std::basic_string<CharT, Traits, Alloc>& fmt,  
6275 - const Streamable& tp)  
6276 - -> decltype(to_stream(std::declval<std::basic_ostream<CharT, Traits>&>(), fmt.c_str(), tp),  
6277 - std::basic_string<CharT, Traits, Alloc>{})  
6278 -{  
6279 - std::basic_ostringstream<CharT, Traits, Alloc> os;  
6280 - os.exceptions(std::ios::failbit | std::ios::badbit);  
6281 - os.imbue(loc);  
6282 - to_stream(os, fmt.c_str(), tp);  
6283 - return os.str();  
6284 -}  
6285 -  
6286 -template <class CharT, class Traits, class Alloc, class Streamable>  
6287 -auto  
6288 -format(const std::basic_string<CharT, Traits, Alloc>& fmt, const Streamable& tp)  
6289 - -> decltype(to_stream(std::declval<std::basic_ostream<CharT, Traits>&>(), fmt.c_str(), tp),  
6290 - std::basic_string<CharT, Traits, Alloc>{})  
6291 -{  
6292 - std::basic_ostringstream<CharT, Traits, Alloc> os;  
6293 - os.exceptions(std::ios::failbit | std::ios::badbit);  
6294 - to_stream(os, fmt.c_str(), tp);  
6295 - return os.str();  
6296 -}  
6297 -  
6298 -// parse  
6299 -  
6300 -namespace detail  
6301 -{  
6302 -  
6303 -template <class CharT, class Traits>  
6304 -bool  
6305 -read_char(std::basic_istream<CharT, Traits>& is, CharT fmt, std::ios::iostate& err)  
6306 -{  
6307 - auto ic = is.get();  
6308 - if (Traits::eq_int_type(ic, Traits::eof()) ||  
6309 - !Traits::eq(Traits::to_char_type(ic), fmt))  
6310 - {  
6311 - err |= std::ios::failbit;  
6312 - is.setstate(std::ios::failbit);  
6313 - return false;  
6314 - }  
6315 - return true;  
6316 -}  
6317 -  
6318 -template <class CharT, class Traits>  
6319 -unsigned  
6320 -read_unsigned(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10)  
6321 -{  
6322 - unsigned x = 0;  
6323 - unsigned count = 0;  
6324 - while (true)  
6325 - {  
6326 - auto ic = is.peek();  
6327 - if (Traits::eq_int_type(ic, Traits::eof()))  
6328 - break;  
6329 - auto c = static_cast<char>(Traits::to_char_type(ic));  
6330 - if (!('0' <= c && c <= '9'))  
6331 - break;  
6332 - (void)is.get();  
6333 - ++count;  
6334 - x = 10*x + static_cast<unsigned>(c - '0');  
6335 - if (count == M)  
6336 - break;  
6337 - }  
6338 - if (count < m)  
6339 - is.setstate(std::ios::failbit);  
6340 - return x;  
6341 -}  
6342 -  
6343 -template <class CharT, class Traits>  
6344 -int  
6345 -read_signed(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10)  
6346 -{  
6347 - auto ic = is.peek();  
6348 - if (!Traits::eq_int_type(ic, Traits::eof()))  
6349 - {  
6350 - auto c = static_cast<char>(Traits::to_char_type(ic));  
6351 - if (('0' <= c && c <= '9') || c == '-' || c == '+')  
6352 - {  
6353 - if (c == '-' || c == '+')  
6354 - (void)is.get();  
6355 - auto x = static_cast<int>(read_unsigned(is, std::max(m, 1u), M));  
6356 - if (!is.fail())  
6357 - {  
6358 - if (c == '-')  
6359 - x = -x;  
6360 - return x;  
6361 - }  
6362 - }  
6363 - }  
6364 - if (m > 0)  
6365 - is.setstate(std::ios::failbit);  
6366 - return 0;  
6367 -}  
6368 -  
6369 -template <class CharT, class Traits>  
6370 -long double  
6371 -read_long_double(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10)  
6372 -{  
6373 - unsigned count = 0;  
6374 - unsigned fcount = 0;  
6375 - unsigned long long i = 0;  
6376 - unsigned long long f = 0;  
6377 - bool parsing_fraction = false;  
6378 -#if ONLY_C_LOCALE  
6379 - typename Traits::int_type decimal_point = '.';  
6380 -#else  
6381 - auto decimal_point = Traits::to_int_type(  
6382 - std::use_facet<std::numpunct<CharT>>(is.getloc()).decimal_point());  
6383 -#endif  
6384 - while (true)  
6385 - {  
6386 - auto ic = is.peek();  
6387 - if (Traits::eq_int_type(ic, Traits::eof()))  
6388 - break;  
6389 - if (Traits::eq_int_type(ic, decimal_point))  
6390 - {  
6391 - decimal_point = Traits::eof();  
6392 - parsing_fraction = true;  
6393 - }  
6394 - else  
6395 - {  
6396 - auto c = static_cast<char>(Traits::to_char_type(ic));  
6397 - if (!('0' <= c && c <= '9'))  
6398 - break;  
6399 - if (!parsing_fraction)  
6400 - {  
6401 - i = 10*i + static_cast<unsigned>(c - '0');  
6402 - }  
6403 - else  
6404 - {  
6405 - f = 10*f + static_cast<unsigned>(c - '0');  
6406 - ++fcount;  
6407 - }  
6408 - }  
6409 - (void)is.get();  
6410 - if (++count == M)  
6411 - break;  
6412 - }  
6413 - if (count < m)  
6414 - {  
6415 - is.setstate(std::ios::failbit);  
6416 - return 0;  
6417 - }  
6418 - return static_cast<long double>(i) + static_cast<long double>(f)/std::pow(10.L, fcount);  
6419 -}  
6420 -  
6421 -struct rs  
6422 -{  
6423 - int& i;  
6424 - unsigned m;  
6425 - unsigned M;  
6426 -};  
6427 -  
6428 -struct ru  
6429 -{  
6430 - int& i;  
6431 - unsigned m;  
6432 - unsigned M;  
6433 -};  
6434 -  
6435 -struct rld  
6436 -{  
6437 - long double& i;  
6438 - unsigned m;  
6439 - unsigned M;  
6440 -};  
6441 -  
6442 -template <class CharT, class Traits>  
6443 -void  
6444 -read(std::basic_istream<CharT, Traits>&)  
6445 -{  
6446 -}  
6447 -  
6448 -template <class CharT, class Traits, class ...Args>  
6449 -void  
6450 -read(std::basic_istream<CharT, Traits>& is, CharT a0, Args&& ...args);  
6451 -  
6452 -template <class CharT, class Traits, class ...Args>  
6453 -void  
6454 -read(std::basic_istream<CharT, Traits>& is, rs a0, Args&& ...args);  
6455 -  
6456 -template <class CharT, class Traits, class ...Args>  
6457 -void  
6458 -read(std::basic_istream<CharT, Traits>& is, ru a0, Args&& ...args);  
6459 -  
6460 -template <class CharT, class Traits, class ...Args>  
6461 -void  
6462 -read(std::basic_istream<CharT, Traits>& is, int a0, Args&& ...args);  
6463 -  
6464 -template <class CharT, class Traits, class ...Args>  
6465 -void  
6466 -read(std::basic_istream<CharT, Traits>& is, rld a0, Args&& ...args);  
6467 -  
6468 -template <class CharT, class Traits, class ...Args>  
6469 -void  
6470 -read(std::basic_istream<CharT, Traits>& is, CharT a0, Args&& ...args)  
6471 -{  
6472 - // No-op if a0 == CharT{}  
6473 - if (a0 != CharT{})  
6474 - {  
6475 - auto ic = is.peek();  
6476 - if (Traits::eq_int_type(ic, Traits::eof()))  
6477 - {  
6478 - is.setstate(std::ios::failbit | std::ios::eofbit);  
6479 - return;  
6480 - }  
6481 - if (!Traits::eq(Traits::to_char_type(ic), a0))  
6482 - {  
6483 - is.setstate(std::ios::failbit);  
6484 - return;  
6485 - }  
6486 - (void)is.get();  
6487 - }  
6488 - read(is, std::forward<Args>(args)...);  
6489 -}  
6490 -  
6491 -template <class CharT, class Traits, class ...Args>  
6492 -void  
6493 -read(std::basic_istream<CharT, Traits>& is, rs a0, Args&& ...args)  
6494 -{  
6495 - auto x = read_signed(is, a0.m, a0.M);  
6496 - if (is.fail())  
6497 - return;  
6498 - a0.i = x;  
6499 - read(is, std::forward<Args>(args)...);  
6500 -}  
6501 -  
6502 -template <class CharT, class Traits, class ...Args>  
6503 -void  
6504 -read(std::basic_istream<CharT, Traits>& is, ru a0, Args&& ...args)  
6505 -{  
6506 - auto x = read_unsigned(is, a0.m, a0.M);  
6507 - if (is.fail())  
6508 - return;  
6509 - a0.i = static_cast<int>(x);  
6510 - read(is, std::forward<Args>(args)...);  
6511 -}  
6512 -  
6513 -template <class CharT, class Traits, class ...Args>  
6514 -void  
6515 -read(std::basic_istream<CharT, Traits>& is, int a0, Args&& ...args)  
6516 -{  
6517 - if (a0 != -1)  
6518 - {  
6519 - auto u = static_cast<unsigned>(a0);  
6520 - CharT buf[std::numeric_limits<unsigned>::digits10+2u] = {};  
6521 - auto e = buf;  
6522 - do  
6523 - {  
6524 - *e++ = static_cast<CharT>(CharT(u % 10) + CharT{'0'});  
6525 - u /= 10;  
6526 - } while (u > 0);  
6527 - std::reverse(buf, e);  
6528 - for (auto p = buf; p != e && is.rdstate() == std::ios::goodbit; ++p)  
6529 - read(is, *p);  
6530 - }  
6531 - if (is.rdstate() == std::ios::goodbit)  
6532 - read(is, std::forward<Args>(args)...);  
6533 -}  
6534 -  
6535 -template <class CharT, class Traits, class ...Args>  
6536 -void  
6537 -read(std::basic_istream<CharT, Traits>& is, rld a0, Args&& ...args)  
6538 -{  
6539 - auto x = read_long_double(is, a0.m, a0.M);  
6540 - if (is.fail())  
6541 - return;  
6542 - a0.i = x;  
6543 - read(is, std::forward<Args>(args)...);  
6544 -}  
6545 -  
6546 -template <class T, class CharT, class Traits>  
6547 -inline  
6548 -void  
6549 -checked_set(T& value, T from, T not_a_value, std::basic_ios<CharT, Traits>& is)  
6550 -{  
6551 - if (!is.fail())  
6552 - {  
6553 - if (value == not_a_value)  
6554 - value = std::move(from);  
6555 - else if (value != from)  
6556 - is.setstate(std::ios::failbit);  
6557 - }  
6558 -}  
6559 -  
6560 -} // namespace detail;  
6561 -  
6562 -template <class CharT, class Traits, class Duration, class Alloc = std::allocator<CharT>>  
6563 -std::basic_istream<CharT, Traits>&  
6564 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,  
6565 - fields<Duration>& fds, std::basic_string<CharT, Traits, Alloc>* abbrev,  
6566 - std::chrono::minutes* offset)  
6567 -{  
6568 - using std::numeric_limits;  
6569 - using std::ios;  
6570 - using std::chrono::duration;  
6571 - using std::chrono::duration_cast;  
6572 - using std::chrono::seconds;  
6573 - using std::chrono::minutes;  
6574 - using std::chrono::hours;  
6575 - using detail::round_i;  
6576 - typename std::basic_istream<CharT, Traits>::sentry ok{is, true};  
6577 - if (ok)  
6578 - {  
6579 - date::detail::save_istream<CharT, Traits> ss(is);  
6580 - is.fill(' ');  
6581 - is.flags(std::ios::skipws | std::ios::dec);  
6582 - is.width(0);  
6583 -#if !ONLY_C_LOCALE  
6584 - auto& f = std::use_facet<std::time_get<CharT>>(is.getloc());  
6585 - std::tm tm{};  
6586 -#endif  
6587 - const CharT* command = nullptr;  
6588 - auto modified = CharT{};  
6589 - auto width = -1;  
6590 -  
6591 - CONSTDATA int not_a_year = numeric_limits<short>::min();  
6592 - CONSTDATA int not_a_2digit_year = 100;  
6593 - CONSTDATA int not_a_century = not_a_year / 100;  
6594 - CONSTDATA int not_a_month = 0;  
6595 - CONSTDATA int not_a_day = 0;  
6596 - CONSTDATA int not_a_hour = numeric_limits<int>::min();  
6597 - CONSTDATA int not_a_hour_12_value = 0;  
6598 - CONSTDATA int not_a_minute = not_a_hour;  
6599 - CONSTDATA Duration not_a_second = Duration::min();  
6600 - CONSTDATA int not_a_doy = -1;  
6601 - CONSTDATA int not_a_weekday = 8;  
6602 - CONSTDATA int not_a_week_num = 100;  
6603 - CONSTDATA int not_a_ampm = -1;  
6604 - CONSTDATA minutes not_a_offset = minutes::min();  
6605 -  
6606 - int Y = not_a_year; // c, F, Y *  
6607 - int y = not_a_2digit_year; // D, x, y *  
6608 - int g = not_a_2digit_year; // g *  
6609 - int G = not_a_year; // G *  
6610 - int C = not_a_century; // C *  
6611 - int m = not_a_month; // b, B, h, m, c, D, F, x *  
6612 - int d = not_a_day; // c, d, D, e, F, x *  
6613 - int j = not_a_doy; // j *  
6614 - int wd = not_a_weekday; // a, A, u, w *  
6615 - int H = not_a_hour; // c, H, R, T, X *  
6616 - int I = not_a_hour_12_value; // I, r *  
6617 - int p = not_a_ampm; // p, r *  
6618 - int M = not_a_minute; // c, M, r, R, T, X *  
6619 - Duration s = not_a_second; // c, r, S, T, X *  
6620 - int U = not_a_week_num; // U *  
6621 - int V = not_a_week_num; // V *  
6622 - int W = not_a_week_num; // W *  
6623 - std::basic_string<CharT, Traits, Alloc> temp_abbrev; // Z *  
6624 - minutes temp_offset = not_a_offset; // z *  
6625 -  
6626 - using detail::read;  
6627 - using detail::rs;  
6628 - using detail::ru;  
6629 - using detail::rld;  
6630 - using detail::checked_set;  
6631 - for (; *fmt != CharT{} && !is.fail(); ++fmt)  
6632 - {  
6633 - switch (*fmt)  
6634 - {  
6635 - case 'a':  
6636 - case 'A':  
6637 - case 'u':  
6638 - case 'w': // wd: a, A, u, w  
6639 - if (command)  
6640 - {  
6641 - int trial_wd = not_a_weekday;  
6642 - if (*fmt == 'a' || *fmt == 'A')  
6643 - {  
6644 - if (modified == CharT{})  
6645 - {  
6646 -#if !ONLY_C_LOCALE  
6647 - ios::iostate err = ios::goodbit;  
6648 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
6649 - is.setstate(err);  
6650 - if (!is.fail())  
6651 - trial_wd = tm.tm_wday;  
6652 -#else  
6653 - auto nm = detail::weekday_names();  
6654 - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;  
6655 - if (!is.fail())  
6656 - trial_wd = i % 7;  
6657 -#endif  
6658 - }  
6659 - else  
6660 - read(is, CharT{'%'}, width, modified, *fmt);  
6661 - }  
6662 - else // *fmt == 'u' || *fmt == 'w'  
6663 - {  
6664 -#if !ONLY_C_LOCALE  
6665 - if (modified == CharT{})  
6666 -#else  
6667 - if (modified != CharT{'E'})  
6668 -#endif  
6669 - {  
6670 - read(is, ru{trial_wd, 1, width == -1 ?  
6671 - 1u : static_cast<unsigned>(width)});  
6672 - if (!is.fail())  
6673 - {  
6674 - if (*fmt == 'u')  
6675 - {  
6676 - if (!(1 <= trial_wd && trial_wd <= 7))  
6677 - {  
6678 - trial_wd = not_a_weekday;  
6679 - is.setstate(ios::failbit);  
6680 - }  
6681 - else if (trial_wd == 7)  
6682 - trial_wd = 0;  
6683 - }  
6684 - else // *fmt == 'w'  
6685 - {  
6686 - if (!(0 <= trial_wd && trial_wd <= 6))  
6687 - {  
6688 - trial_wd = not_a_weekday;  
6689 - is.setstate(ios::failbit);  
6690 - }  
6691 - }  
6692 - }  
6693 - }  
6694 -#if !ONLY_C_LOCALE  
6695 - else if (modified == CharT{'O'})  
6696 - {  
6697 - ios::iostate err = ios::goodbit;  
6698 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
6699 - is.setstate(err);  
6700 - if (!is.fail())  
6701 - trial_wd = tm.tm_wday;  
6702 - }  
6703 -#endif  
6704 - else  
6705 - read(is, CharT{'%'}, width, modified, *fmt);  
6706 - }  
6707 - if (trial_wd != not_a_weekday)  
6708 - checked_set(wd, trial_wd, not_a_weekday, is);  
6709 - }  
6710 - else // !command  
6711 - read(is, *fmt);  
6712 - command = nullptr;  
6713 - width = -1;  
6714 - modified = CharT{};  
6715 - break;  
6716 - case 'b':  
6717 - case 'B':  
6718 - case 'h':  
6719 - if (command)  
6720 - {  
6721 - if (modified == CharT{})  
6722 - {  
6723 - int ttm = not_a_month;  
6724 -#if !ONLY_C_LOCALE  
6725 - ios::iostate err = ios::goodbit;  
6726 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
6727 - if ((err & ios::failbit) == 0)  
6728 - ttm = tm.tm_mon + 1;  
6729 - is.setstate(err);  
6730 -#else  
6731 - auto nm = detail::month_names();  
6732 - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;  
6733 - if (!is.fail())  
6734 - ttm = i % 12 + 1;  
6735 -#endif  
6736 - checked_set(m, ttm, not_a_month, is);  
6737 - }  
6738 - else  
6739 - read(is, CharT{'%'}, width, modified, *fmt);  
6740 - command = nullptr;  
6741 - width = -1;  
6742 - modified = CharT{};  
6743 - }  
6744 - else  
6745 - read(is, *fmt);  
6746 - break;  
6747 - case 'c':  
6748 - if (command)  
6749 - {  
6750 - if (modified != CharT{'O'})  
6751 - {  
6752 -#if !ONLY_C_LOCALE  
6753 - ios::iostate err = ios::goodbit;  
6754 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
6755 - if ((err & ios::failbit) == 0)  
6756 - {  
6757 - checked_set(Y, tm.tm_year + 1900, not_a_year, is);  
6758 - checked_set(m, tm.tm_mon + 1, not_a_month, is);  
6759 - checked_set(d, tm.tm_mday, not_a_day, is);  
6760 - checked_set(H, tm.tm_hour, not_a_hour, is);  
6761 - checked_set(M, tm.tm_min, not_a_minute, is);  
6762 - checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),  
6763 - not_a_second, is);  
6764 - }  
6765 - is.setstate(err);  
6766 -#else  
6767 - // "%a %b %e %T %Y"  
6768 - auto nm = detail::weekday_names();  
6769 - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;  
6770 - checked_set(wd, static_cast<int>(i % 7), not_a_weekday, is);  
6771 - ws(is);  
6772 - nm = detail::month_names();  
6773 - i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;  
6774 - checked_set(m, static_cast<int>(i % 12 + 1), not_a_month, is);  
6775 - ws(is);  
6776 - int td = not_a_day;  
6777 - read(is, rs{td, 1, 2});  
6778 - checked_set(d, td, not_a_day, is);  
6779 - ws(is);  
6780 - using dfs = detail::decimal_format_seconds<Duration>;  
6781 - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;  
6782 - int tH;  
6783 - int tM;  
6784 - long double S{};  
6785 - read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2},  
6786 - CharT{':'}, rld{S, 1, w});  
6787 - checked_set(H, tH, not_a_hour, is);  
6788 - checked_set(M, tM, not_a_minute, is);  
6789 - checked_set(s, round_i<Duration>(duration<long double>{S}),  
6790 - not_a_second, is);  
6791 - ws(is);  
6792 - int tY = not_a_year;  
6793 - read(is, rs{tY, 1, 4u});  
6794 - checked_set(Y, tY, not_a_year, is);  
6795 -#endif  
6796 - }  
6797 - else  
6798 - read(is, CharT{'%'}, width, modified, *fmt);  
6799 - command = nullptr;  
6800 - width = -1;  
6801 - modified = CharT{};  
6802 - }  
6803 - else  
6804 - read(is, *fmt);  
6805 - break;  
6806 - case 'x':  
6807 - if (command)  
6808 - {  
6809 - if (modified != CharT{'O'})  
6810 - {  
6811 -#if !ONLY_C_LOCALE  
6812 - ios::iostate err = ios::goodbit;  
6813 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
6814 - if ((err & ios::failbit) == 0)  
6815 - {  
6816 - checked_set(Y, tm.tm_year + 1900, not_a_year, is);  
6817 - checked_set(m, tm.tm_mon + 1, not_a_month, is);  
6818 - checked_set(d, tm.tm_mday, not_a_day, is);  
6819 - }  
6820 - is.setstate(err);  
6821 -#else  
6822 - // "%m/%d/%y"  
6823 - int ty = not_a_2digit_year;  
6824 - int tm = not_a_month;  
6825 - int td = not_a_day;  
6826 - read(is, ru{tm, 1, 2}, CharT{'/'}, ru{td, 1, 2}, CharT{'/'},  
6827 - rs{ty, 1, 2});  
6828 - checked_set(y, ty, not_a_2digit_year, is);  
6829 - checked_set(m, tm, not_a_month, is);  
6830 - checked_set(d, td, not_a_day, is);  
6831 -#endif  
6832 - }  
6833 - else  
6834 - read(is, CharT{'%'}, width, modified, *fmt);  
6835 - command = nullptr;  
6836 - width = -1;  
6837 - modified = CharT{};  
6838 - }  
6839 - else  
6840 - read(is, *fmt);  
6841 - break;  
6842 - case 'X':  
6843 - if (command)  
6844 - {  
6845 - if (modified != CharT{'O'})  
6846 - {  
6847 -#if !ONLY_C_LOCALE  
6848 - ios::iostate err = ios::goodbit;  
6849 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
6850 - if ((err & ios::failbit) == 0)  
6851 - {  
6852 - checked_set(H, tm.tm_hour, not_a_hour, is);  
6853 - checked_set(M, tm.tm_min, not_a_minute, is);  
6854 - checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),  
6855 - not_a_second, is);  
6856 - }  
6857 - is.setstate(err);  
6858 -#else  
6859 - // "%T"  
6860 - using dfs = detail::decimal_format_seconds<Duration>;  
6861 - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;  
6862 - int tH = not_a_hour;  
6863 - int tM = not_a_minute;  
6864 - long double S{};  
6865 - read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2},  
6866 - CharT{':'}, rld{S, 1, w});  
6867 - checked_set(H, tH, not_a_hour, is);  
6868 - checked_set(M, tM, not_a_minute, is);  
6869 - checked_set(s, round_i<Duration>(duration<long double>{S}),  
6870 - not_a_second, is);  
6871 -#endif  
6872 - }  
6873 - else  
6874 - read(is, CharT{'%'}, width, modified, *fmt);  
6875 - command = nullptr;  
6876 - width = -1;  
6877 - modified = CharT{};  
6878 - }  
6879 - else  
6880 - read(is, *fmt);  
6881 - break;  
6882 - case 'C':  
6883 - if (command)  
6884 - {  
6885 - int tC = not_a_century;  
6886 -#if !ONLY_C_LOCALE  
6887 - if (modified == CharT{})  
6888 - {  
6889 -#endif  
6890 - read(is, rs{tC, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
6891 -#if !ONLY_C_LOCALE  
6892 - }  
6893 - else  
6894 - {  
6895 - ios::iostate err = ios::goodbit;  
6896 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
6897 - if ((err & ios::failbit) == 0)  
6898 - {  
6899 - auto tY = tm.tm_year + 1900;  
6900 - tC = (tY >= 0 ? tY : tY-99) / 100;  
6901 - }  
6902 - is.setstate(err);  
6903 - }  
6904 -#endif  
6905 - checked_set(C, tC, not_a_century, is);  
6906 - command = nullptr;  
6907 - width = -1;  
6908 - modified = CharT{};  
6909 - }  
6910 - else  
6911 - read(is, *fmt);  
6912 - break;  
6913 - case 'D':  
6914 - if (command)  
6915 - {  
6916 - if (modified == CharT{})  
6917 - {  
6918 - int tn = not_a_month;  
6919 - int td = not_a_day;  
6920 - int ty = not_a_2digit_year;  
6921 - read(is, ru{tn, 1, 2}, CharT{'\0'}, CharT{'/'}, CharT{'\0'},  
6922 - ru{td, 1, 2}, CharT{'\0'}, CharT{'/'}, CharT{'\0'},  
6923 - rs{ty, 1, 2});  
6924 - checked_set(y, ty, not_a_2digit_year, is);  
6925 - checked_set(m, tn, not_a_month, is);  
6926 - checked_set(d, td, not_a_day, is);  
6927 - }  
6928 - else  
6929 - read(is, CharT{'%'}, width, modified, *fmt);  
6930 - command = nullptr;  
6931 - width = -1;  
6932 - modified = CharT{};  
6933 - }  
6934 - else  
6935 - read(is, *fmt);  
6936 - break;  
6937 - case 'F':  
6938 - if (command)  
6939 - {  
6940 - if (modified == CharT{})  
6941 - {  
6942 - int tY = not_a_year;  
6943 - int tn = not_a_month;  
6944 - int td = not_a_day;  
6945 - read(is, rs{tY, 1, width == -1 ? 4u : static_cast<unsigned>(width)},  
6946 - CharT{'-'}, ru{tn, 1, 2}, CharT{'-'}, ru{td, 1, 2});  
6947 - checked_set(Y, tY, not_a_year, is);  
6948 - checked_set(m, tn, not_a_month, is);  
6949 - checked_set(d, td, not_a_day, is);  
6950 - }  
6951 - else  
6952 - read(is, CharT{'%'}, width, modified, *fmt);  
6953 - command = nullptr;  
6954 - width = -1;  
6955 - modified = CharT{};  
6956 - }  
6957 - else  
6958 - read(is, *fmt);  
6959 - break;  
6960 - case 'd':  
6961 - case 'e':  
6962 - if (command)  
6963 - {  
6964 -#if !ONLY_C_LOCALE  
6965 - if (modified == CharT{})  
6966 -#else  
6967 - if (modified != CharT{'E'})  
6968 -#endif  
6969 - {  
6970 - int td = not_a_day;  
6971 - read(is, rs{td, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
6972 - checked_set(d, td, not_a_day, is);  
6973 - }  
6974 -#if !ONLY_C_LOCALE  
6975 - else if (modified == CharT{'O'})  
6976 - {  
6977 - ios::iostate err = ios::goodbit;  
6978 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
6979 - command = nullptr;  
6980 - width = -1;  
6981 - modified = CharT{};  
6982 - if ((err & ios::failbit) == 0)  
6983 - checked_set(d, tm.tm_mday, not_a_day, is);  
6984 - is.setstate(err);  
6985 - }  
6986 -#endif  
6987 - else  
6988 - read(is, CharT{'%'}, width, modified, *fmt);  
6989 - command = nullptr;  
6990 - width = -1;  
6991 - modified = CharT{};  
6992 - }  
6993 - else  
6994 - read(is, *fmt);  
6995 - break;  
6996 - case 'H':  
6997 - if (command)  
6998 - {  
6999 -#if !ONLY_C_LOCALE  
7000 - if (modified == CharT{})  
7001 -#else  
7002 - if (modified != CharT{'E'})  
7003 -#endif  
7004 - {  
7005 - int tH = not_a_hour;  
7006 - read(is, ru{tH, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
7007 - checked_set(H, tH, not_a_hour, is);  
7008 - }  
7009 -#if !ONLY_C_LOCALE  
7010 - else if (modified == CharT{'O'})  
7011 - {  
7012 - ios::iostate err = ios::goodbit;  
7013 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
7014 - if ((err & ios::failbit) == 0)  
7015 - checked_set(H, tm.tm_hour, not_a_hour, is);  
7016 - is.setstate(err);  
7017 - }  
7018 -#endif  
7019 - else  
7020 - read(is, CharT{'%'}, width, modified, *fmt);  
7021 - command = nullptr;  
7022 - width = -1;  
7023 - modified = CharT{};  
7024 - }  
7025 - else  
7026 - read(is, *fmt);  
7027 - break;  
7028 - case 'I':  
7029 - if (command)  
7030 - {  
7031 - if (modified == CharT{})  
7032 - {  
7033 - int tI = not_a_hour_12_value;  
7034 - // reads in an hour into I, but most be in [1, 12]  
7035 - read(is, rs{tI, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
7036 - if (!(1 <= tI && tI <= 12))  
7037 - is.setstate(ios::failbit);  
7038 - checked_set(I, tI, not_a_hour_12_value, is);  
7039 - }  
7040 - else  
7041 - read(is, CharT{'%'}, width, modified, *fmt);  
7042 - command = nullptr;  
7043 - width = -1;  
7044 - modified = CharT{};  
7045 - }  
7046 - else  
7047 - read(is, *fmt);  
7048 - break;  
7049 - case 'j':  
7050 - if (command)  
7051 - {  
7052 - if (modified == CharT{})  
7053 - {  
7054 - int tj = not_a_doy;  
7055 - read(is, ru{tj, 1, width == -1 ? 3u : static_cast<unsigned>(width)});  
7056 - checked_set(j, tj, not_a_doy, is);  
7057 - }  
7058 - else  
7059 - read(is, CharT{'%'}, width, modified, *fmt);  
7060 - command = nullptr;  
7061 - width = -1;  
7062 - modified = CharT{};  
7063 - }  
7064 - else  
7065 - read(is, *fmt);  
7066 - break;  
7067 - case 'M':  
7068 - if (command)  
7069 - {  
7070 -#if !ONLY_C_LOCALE  
7071 - if (modified == CharT{})  
7072 -#else  
7073 - if (modified != CharT{'E'})  
7074 -#endif  
7075 - {  
7076 - int tM = not_a_minute;  
7077 - read(is, ru{tM, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
7078 - checked_set(M, tM, not_a_minute, is);  
7079 - }  
7080 -#if !ONLY_C_LOCALE  
7081 - else if (modified == CharT{'O'})  
7082 - {  
7083 - ios::iostate err = ios::goodbit;  
7084 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
7085 - if ((err & ios::failbit) == 0)  
7086 - checked_set(M, tm.tm_min, not_a_minute, is);  
7087 - is.setstate(err);  
7088 - }  
7089 -#endif  
7090 - else  
7091 - read(is, CharT{'%'}, width, modified, *fmt);  
7092 - command = nullptr;  
7093 - width = -1;  
7094 - modified = CharT{};  
7095 - }  
7096 - else  
7097 - read(is, *fmt);  
7098 - break;  
7099 - case 'm':  
7100 - if (command)  
7101 - {  
7102 -#if !ONLY_C_LOCALE  
7103 - if (modified == CharT{})  
7104 -#else  
7105 - if (modified != CharT{'E'})  
7106 -#endif  
7107 - {  
7108 - int tn = not_a_month;  
7109 - read(is, rs{tn, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
7110 - checked_set(m, tn, not_a_month, is);  
7111 - }  
7112 -#if !ONLY_C_LOCALE  
7113 - else if (modified == CharT{'O'})  
7114 - {  
7115 - ios::iostate err = ios::goodbit;  
7116 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
7117 - if ((err & ios::failbit) == 0)  
7118 - checked_set(m, tm.tm_mon + 1, not_a_month, is);  
7119 - is.setstate(err);  
7120 - }  
7121 -#endif  
7122 - else  
7123 - read(is, CharT{'%'}, width, modified, *fmt);  
7124 - command = nullptr;  
7125 - width = -1;  
7126 - modified = CharT{};  
7127 - }  
7128 - else  
7129 - read(is, *fmt);  
7130 - break;  
7131 - case 'n':  
7132 - case 't':  
7133 - if (command)  
7134 - {  
7135 - if (modified == CharT{})  
7136 - {  
7137 - // %n matches a single white space character  
7138 - // %t matches 0 or 1 white space characters  
7139 - auto ic = is.peek();  
7140 - if (Traits::eq_int_type(ic, Traits::eof()))  
7141 - {  
7142 - ios::iostate err = ios::eofbit;  
7143 - if (*fmt == 'n')  
7144 - err |= ios::failbit;  
7145 - is.setstate(err);  
7146 - break;  
7147 - }  
7148 - if (isspace(ic))  
7149 - {  
7150 - (void)is.get();  
7151 - }  
7152 - else if (*fmt == 'n')  
7153 - is.setstate(ios::failbit);  
7154 - }  
7155 - else  
7156 - read(is, CharT{'%'}, width, modified, *fmt);  
7157 - command = nullptr;  
7158 - width = -1;  
7159 - modified = CharT{};  
7160 - }  
7161 - else  
7162 - read(is, *fmt);  
7163 - break;  
7164 - case 'p':  
7165 - if (command)  
7166 - {  
7167 - if (modified == CharT{})  
7168 - {  
7169 - int tp = not_a_ampm;  
7170 -#if !ONLY_C_LOCALE  
7171 - tm = std::tm{};  
7172 - tm.tm_hour = 1;  
7173 - ios::iostate err = ios::goodbit;  
7174 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
7175 - is.setstate(err);  
7176 - if (tm.tm_hour == 1)  
7177 - tp = 0;  
7178 - else if (tm.tm_hour == 13)  
7179 - tp = 1;  
7180 - else  
7181 - is.setstate(err);  
7182 -#else  
7183 - auto nm = detail::ampm_names();  
7184 - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;  
7185 - tp = static_cast<decltype(tp)>(i);  
7186 -#endif  
7187 - checked_set(p, tp, not_a_ampm, is);  
7188 - }  
7189 - else  
7190 - read(is, CharT{'%'}, width, modified, *fmt);  
7191 - command = nullptr;  
7192 - width = -1;  
7193 - modified = CharT{};  
7194 - }  
7195 - else  
7196 - read(is, *fmt);  
7197 -  
7198 - break;  
7199 - case 'r':  
7200 - if (command)  
7201 - {  
7202 - if (modified == CharT{})  
7203 - {  
7204 -#if !ONLY_C_LOCALE  
7205 - ios::iostate err = ios::goodbit;  
7206 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
7207 - if ((err & ios::failbit) == 0)  
7208 - {  
7209 - checked_set(H, tm.tm_hour, not_a_hour, is);  
7210 - checked_set(M, tm.tm_min, not_a_hour, is);  
7211 - checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),  
7212 - not_a_second, is);  
7213 - }  
7214 - is.setstate(err);  
7215 -#else  
7216 - // "%I:%M:%S %p"  
7217 - using dfs = detail::decimal_format_seconds<Duration>;  
7218 - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;  
7219 - long double S{};  
7220 - int tI = not_a_hour_12_value;  
7221 - int tM = not_a_minute;  
7222 - read(is, ru{tI, 1, 2}, CharT{':'}, ru{tM, 1, 2},  
7223 - CharT{':'}, rld{S, 1, w});  
7224 - checked_set(I, tI, not_a_hour_12_value, is);  
7225 - checked_set(M, tM, not_a_minute, is);  
7226 - checked_set(s, round_i<Duration>(duration<long double>{S}),  
7227 - not_a_second, is);  
7228 - ws(is);  
7229 - auto nm = detail::ampm_names();  
7230 - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;  
7231 - checked_set(p, static_cast<int>(i), not_a_ampm, is);  
7232 -#endif  
7233 - }  
7234 - else  
7235 - read(is, CharT{'%'}, width, modified, *fmt);  
7236 - command = nullptr;  
7237 - width = -1;  
7238 - modified = CharT{};  
7239 - }  
7240 - else  
7241 - read(is, *fmt);  
7242 - break;  
7243 - case 'R':  
7244 - if (command)  
7245 - {  
7246 - if (modified == CharT{})  
7247 - {  
7248 - int tH = not_a_hour;  
7249 - int tM = not_a_minute;  
7250 - read(is, ru{tH, 1, 2}, CharT{'\0'}, CharT{':'}, CharT{'\0'},  
7251 - ru{tM, 1, 2}, CharT{'\0'});  
7252 - checked_set(H, tH, not_a_hour, is);  
7253 - checked_set(M, tM, not_a_minute, is);  
7254 - }  
7255 - else  
7256 - read(is, CharT{'%'}, width, modified, *fmt);  
7257 - command = nullptr;  
7258 - width = -1;  
7259 - modified = CharT{};  
7260 - }  
7261 - else  
7262 - read(is, *fmt);  
7263 - break;  
7264 - case 'S':  
7265 - if (command)  
7266 - {  
7267 - #if !ONLY_C_LOCALE  
7268 - if (modified == CharT{})  
7269 -#else  
7270 - if (modified != CharT{'E'})  
7271 -#endif  
7272 - {  
7273 - using dfs = detail::decimal_format_seconds<Duration>;  
7274 - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;  
7275 - long double S{};  
7276 - read(is, rld{S, 1, width == -1 ? w : static_cast<unsigned>(width)});  
7277 - checked_set(s, round_i<Duration>(duration<long double>{S}),  
7278 - not_a_second, is);  
7279 - }  
7280 -#if !ONLY_C_LOCALE  
7281 - else if (modified == CharT{'O'})  
7282 - {  
7283 - ios::iostate err = ios::goodbit;  
7284 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
7285 - if ((err & ios::failbit) == 0)  
7286 - checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),  
7287 - not_a_second, is);  
7288 - is.setstate(err);  
7289 - }  
7290 -#endif  
7291 - else  
7292 - read(is, CharT{'%'}, width, modified, *fmt);  
7293 - command = nullptr;  
7294 - width = -1;  
7295 - modified = CharT{};  
7296 - }  
7297 - else  
7298 - read(is, *fmt);  
7299 - break;  
7300 - case 'T':  
7301 - if (command)  
7302 - {  
7303 - if (modified == CharT{})  
7304 - {  
7305 - using dfs = detail::decimal_format_seconds<Duration>;  
7306 - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;  
7307 - int tH = not_a_hour;  
7308 - int tM = not_a_minute;  
7309 - long double S{};  
7310 - read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2},  
7311 - CharT{':'}, rld{S, 1, w});  
7312 - checked_set(H, tH, not_a_hour, is);  
7313 - checked_set(M, tM, not_a_minute, is);  
7314 - checked_set(s, round_i<Duration>(duration<long double>{S}),  
7315 - not_a_second, is);  
7316 - }  
7317 - else  
7318 - read(is, CharT{'%'}, width, modified, *fmt);  
7319 - command = nullptr;  
7320 - width = -1;  
7321 - modified = CharT{};  
7322 - }  
7323 - else  
7324 - read(is, *fmt);  
7325 - break;  
7326 - case 'Y':  
7327 - if (command)  
7328 - {  
7329 -#if !ONLY_C_LOCALE  
7330 - if (modified == CharT{})  
7331 -#else  
7332 - if (modified != CharT{'O'})  
7333 -#endif  
7334 - {  
7335 - int tY = not_a_year;  
7336 - read(is, rs{tY, 1, width == -1 ? 4u : static_cast<unsigned>(width)});  
7337 - checked_set(Y, tY, not_a_year, is);  
7338 - }  
7339 -#if !ONLY_C_LOCALE  
7340 - else if (modified == CharT{'E'})  
7341 - {  
7342 - ios::iostate err = ios::goodbit;  
7343 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
7344 - if ((err & ios::failbit) == 0)  
7345 - checked_set(Y, tm.tm_year + 1900, not_a_year, is);  
7346 - is.setstate(err);  
7347 - }  
7348 -#endif  
7349 - else  
7350 - read(is, CharT{'%'}, width, modified, *fmt);  
7351 - command = nullptr;  
7352 - width = -1;  
7353 - modified = CharT{};  
7354 - }  
7355 - else  
7356 - read(is, *fmt);  
7357 - break;  
7358 - case 'y':  
7359 - if (command)  
7360 - {  
7361 -#if !ONLY_C_LOCALE  
7362 - if (modified == CharT{})  
7363 -#endif  
7364 - {  
7365 - int ty = not_a_2digit_year;  
7366 - read(is, ru{ty, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
7367 - checked_set(y, ty, not_a_2digit_year, is);  
7368 - }  
7369 -#if !ONLY_C_LOCALE  
7370 - else  
7371 - {  
7372 - ios::iostate err = ios::goodbit;  
7373 - f.get(is, nullptr, is, err, &tm, command, fmt+1);  
7374 - if ((err & ios::failbit) == 0)  
7375 - checked_set(Y, tm.tm_year + 1900, not_a_year, is);  
7376 - is.setstate(err);  
7377 - }  
7378 -#endif  
7379 - command = nullptr;  
7380 - width = -1;  
7381 - modified = CharT{};  
7382 - }  
7383 - else  
7384 - read(is, *fmt);  
7385 - break;  
7386 - case 'g':  
7387 - if (command)  
7388 - {  
7389 - if (modified == CharT{})  
7390 - {  
7391 - int tg = not_a_2digit_year;  
7392 - read(is, ru{tg, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
7393 - checked_set(g, tg, not_a_2digit_year, is);  
7394 - }  
7395 - else  
7396 - read(is, CharT{'%'}, width, modified, *fmt);  
7397 - command = nullptr;  
7398 - width = -1;  
7399 - modified = CharT{};  
7400 - }  
7401 - else  
7402 - read(is, *fmt);  
7403 - break;  
7404 - case 'G':  
7405 - if (command)  
7406 - {  
7407 - if (modified == CharT{})  
7408 - {  
7409 - int tG = not_a_year;  
7410 - read(is, rs{tG, 1, width == -1 ? 4u : static_cast<unsigned>(width)});  
7411 - checked_set(G, tG, not_a_year, is);  
7412 - }  
7413 - else  
7414 - read(is, CharT{'%'}, width, modified, *fmt);  
7415 - command = nullptr;  
7416 - width = -1;  
7417 - modified = CharT{};  
7418 - }  
7419 - else  
7420 - read(is, *fmt);  
7421 - break;  
7422 - case 'U':  
7423 - if (command)  
7424 - {  
7425 - if (modified == CharT{})  
7426 - {  
7427 - int tU = not_a_week_num;  
7428 - read(is, ru{tU, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
7429 - checked_set(U, tU, not_a_week_num, is);  
7430 - }  
7431 - else  
7432 - read(is, CharT{'%'}, width, modified, *fmt);  
7433 - command = nullptr;  
7434 - width = -1;  
7435 - modified = CharT{};  
7436 - }  
7437 - else  
7438 - read(is, *fmt);  
7439 - break;  
7440 - case 'V':  
7441 - if (command)  
7442 - {  
7443 - if (modified == CharT{})  
7444 - {  
7445 - int tV = not_a_week_num;  
7446 - read(is, ru{tV, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
7447 - checked_set(V, tV, not_a_week_num, is);  
7448 - }  
7449 - else  
7450 - read(is, CharT{'%'}, width, modified, *fmt);  
7451 - command = nullptr;  
7452 - width = -1;  
7453 - modified = CharT{};  
7454 - }  
7455 - else  
7456 - read(is, *fmt);  
7457 - break;  
7458 - case 'W':  
7459 - if (command)  
7460 - {  
7461 - if (modified == CharT{})  
7462 - {  
7463 - int tW = not_a_week_num;  
7464 - read(is, ru{tW, 1, width == -1 ? 2u : static_cast<unsigned>(width)});  
7465 - checked_set(W, tW, not_a_week_num, is);  
7466 - }  
7467 - else  
7468 - read(is, CharT{'%'}, width, modified, *fmt);  
7469 - command = nullptr;  
7470 - width = -1;  
7471 - modified = CharT{};  
7472 - }  
7473 - else  
7474 - read(is, *fmt);  
7475 - break;  
7476 - case 'E':  
7477 - case 'O':  
7478 - if (command)  
7479 - {  
7480 - if (modified == CharT{})  
7481 - {  
7482 - modified = *fmt;  
7483 - }  
7484 - else  
7485 - {  
7486 - read(is, CharT{'%'}, width, modified, *fmt);  
7487 - command = nullptr;  
7488 - width = -1;  
7489 - modified = CharT{};  
7490 - }  
7491 - }  
7492 - else  
7493 - read(is, *fmt);  
7494 - break;  
7495 - case '%':  
7496 - if (command)  
7497 - {  
7498 - if (modified == CharT{})  
7499 - read(is, *fmt);  
7500 - else  
7501 - read(is, CharT{'%'}, width, modified, *fmt);  
7502 - command = nullptr;  
7503 - width = -1;  
7504 - modified = CharT{};  
7505 - }  
7506 - else  
7507 - command = fmt;  
7508 - break;  
7509 - case 'z':  
7510 - if (command)  
7511 - {  
7512 - int tH, tM;  
7513 - minutes toff = not_a_offset;  
7514 - bool neg = false;  
7515 - auto ic = is.peek();  
7516 - if (!Traits::eq_int_type(ic, Traits::eof()))  
7517 - {  
7518 - auto c = static_cast<char>(Traits::to_char_type(ic));  
7519 - if (c == '-')  
7520 - neg = true;  
7521 - }  
7522 - if (modified == CharT{})  
7523 - {  
7524 - read(is, rs{tH, 2, 2});  
7525 - if (!is.fail())  
7526 - toff = hours{std::abs(tH)};  
7527 - if (is.good())  
7528 - {  
7529 - ic = is.peek();  
7530 - if (!Traits::eq_int_type(ic, Traits::eof()))  
7531 - {  
7532 - auto c = static_cast<char>(Traits::to_char_type(ic));  
7533 - if ('0' <= c && c <= '9')  
7534 - {  
7535 - read(is, ru{tM, 2, 2});  
7536 - if (!is.fail())  
7537 - toff += minutes{tM};  
7538 - }  
7539 - }  
7540 - }  
7541 - }  
7542 - else  
7543 - {  
7544 - read(is, rs{tH, 1, 2});  
7545 - if (!is.fail())  
7546 - toff = hours{std::abs(tH)};  
7547 - if (is.good())  
7548 - {  
7549 - ic = is.peek();  
7550 - if (!Traits::eq_int_type(ic, Traits::eof()))  
7551 - {  
7552 - auto c = static_cast<char>(Traits::to_char_type(ic));  
7553 - if (c == ':')  
7554 - {  
7555 - (void)is.get();  
7556 - read(is, ru{tM, 2, 2});  
7557 - if (!is.fail())  
7558 - toff += minutes{tM};  
7559 - }  
7560 - }  
7561 - }  
7562 - }  
7563 - if (neg)  
7564 - toff = -toff;  
7565 - checked_set(temp_offset, toff, not_a_offset, is);  
7566 - command = nullptr;  
7567 - width = -1;  
7568 - modified = CharT{};  
7569 - }  
7570 - else  
7571 - read(is, *fmt);  
7572 - break;  
7573 - case 'Z':  
7574 - if (command)  
7575 - {  
7576 - if (modified == CharT{})  
7577 - {  
7578 - std::basic_string<CharT, Traits, Alloc> buf;  
7579 - while (is.rdstate() == std::ios::goodbit)  
7580 - {  
7581 - auto i = is.rdbuf()->sgetc();  
7582 - if (Traits::eq_int_type(i, Traits::eof()))  
7583 - {  
7584 - is.setstate(ios::eofbit);  
7585 - break;  
7586 - }  
7587 - auto wc = Traits::to_char_type(i);  
7588 - auto c = static_cast<char>(wc);  
7589 - // is c a valid time zone name or abbreviation character?  
7590 - if (!(CharT{1} < wc && wc < CharT{127}) || !(isalnum(c) ||  
7591 - c == '_' || c == '/' || c == '-' || c == '+'))  
7592 - break;  
7593 - buf.push_back(c);  
7594 - is.rdbuf()->sbumpc();  
7595 - }  
7596 - if (buf.empty())  
7597 - is.setstate(ios::failbit);  
7598 - checked_set(temp_abbrev, buf, {}, is);  
7599 - }  
7600 - else  
7601 - read(is, CharT{'%'}, width, modified, *fmt);  
7602 - command = nullptr;  
7603 - width = -1;  
7604 - modified = CharT{};  
7605 - }  
7606 - else  
7607 - read(is, *fmt);  
7608 - break;  
7609 - default:  
7610 - if (command)  
7611 - {  
7612 - if (width == -1 && modified == CharT{} && '0' <= *fmt && *fmt <= '9')  
7613 - {  
7614 - width = static_cast<char>(*fmt) - '0';  
7615 - while ('0' <= fmt[1] && fmt[1] <= '9')  
7616 - width = 10*width + static_cast<char>(*++fmt) - '0';  
7617 - }  
7618 - else  
7619 - {  
7620 - if (modified == CharT{})  
7621 - read(is, CharT{'%'}, width, *fmt);  
7622 - else  
7623 - read(is, CharT{'%'}, width, modified, *fmt);  
7624 - command = nullptr;  
7625 - width = -1;  
7626 - modified = CharT{};  
7627 - }  
7628 - }  
7629 - else // !command  
7630 - {  
7631 - if (isspace(static_cast<unsigned char>(*fmt)))  
7632 - {  
7633 - // space matches 0 or more white space characters  
7634 - if (is.good())  
7635 - ws(is);  
7636 - }  
7637 - else  
7638 - read(is, *fmt);  
7639 - }  
7640 - break;  
7641 - }  
7642 - }  
7643 - // is.fail() || *fmt == CharT{}  
7644 - if (is.rdstate() == ios::goodbit && command)  
7645 - {  
7646 - if (modified == CharT{})  
7647 - read(is, CharT{'%'}, width);  
7648 - else  
7649 - read(is, CharT{'%'}, width, modified);  
7650 - }  
7651 - if (!is.fail())  
7652 - {  
7653 - if (y != not_a_2digit_year)  
7654 - {  
7655 - // Convert y and an optional C to Y  
7656 - if (!(0 <= y && y <= 99))  
7657 - goto broken;  
7658 - if (C == not_a_century)  
7659 - {  
7660 - if (Y == not_a_year)  
7661 - {  
7662 - if (y >= 69)  
7663 - C = 19;  
7664 - else  
7665 - C = 20;  
7666 - }  
7667 - else  
7668 - {  
7669 - C = (Y >= 0 ? Y : Y-100) / 100;  
7670 - }  
7671 - }  
7672 - int tY;  
7673 - if (C >= 0)  
7674 - tY = 100*C + y;  
7675 - else  
7676 - tY = 100*(C+1) - (y == 0 ? 100 : y);  
7677 - if (Y != not_a_year && Y != tY)  
7678 - goto broken;  
7679 - Y = tY;  
7680 - }  
7681 - if (g != not_a_2digit_year)  
7682 - {  
7683 - // Convert g and an optional C to G  
7684 - if (!(0 <= g && g <= 99))  
7685 - goto broken;  
7686 - if (C == not_a_century)  
7687 - {  
7688 - if (G == not_a_year)  
7689 - {  
7690 - if (g >= 69)  
7691 - C = 19;  
7692 - else  
7693 - C = 20;  
7694 - }  
7695 - else  
7696 - {  
7697 - C = (G >= 0 ? G : G-100) / 100;  
7698 - }  
7699 - }  
7700 - int tG;  
7701 - if (C >= 0)  
7702 - tG = 100*C + g;  
7703 - else  
7704 - tG = 100*(C+1) - (g == 0 ? 100 : g);  
7705 - if (G != not_a_year && G != tG)  
7706 - goto broken;  
7707 - G = tG;  
7708 - }  
7709 - if (Y < static_cast<int>(year::min()) || Y > static_cast<int>(year::max()))  
7710 - Y = not_a_year;  
7711 - bool computed = false;  
7712 - if (G != not_a_year && V != not_a_week_num && wd != not_a_weekday)  
7713 - {  
7714 - year_month_day ymd_trial = sys_days(year{G-1}/December/Thursday[last]) +  
7715 - (Monday-Thursday) + weeks{V-1} +  
7716 - (weekday{static_cast<unsigned>(wd)}-Monday);  
7717 - if (Y == not_a_year)  
7718 - Y = static_cast<int>(ymd_trial.year());  
7719 - else if (year{Y} != ymd_trial.year())  
7720 - goto broken;  
7721 - if (m == not_a_month)  
7722 - m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));  
7723 - else if (month(static_cast<unsigned>(m)) != ymd_trial.month())  
7724 - goto broken;  
7725 - if (d == not_a_day)  
7726 - d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));  
7727 - else if (day(static_cast<unsigned>(d)) != ymd_trial.day())  
7728 - goto broken;  
7729 - computed = true;  
7730 - }  
7731 - if (Y != not_a_year && U != not_a_week_num && wd != not_a_weekday)  
7732 - {  
7733 - year_month_day ymd_trial = sys_days(year{Y}/January/Sunday[1]) +  
7734 - weeks{U-1} +  
7735 - (weekday{static_cast<unsigned>(wd)} - Sunday);  
7736 - if (Y == not_a_year)  
7737 - Y = static_cast<int>(ymd_trial.year());  
7738 - else if (year{Y} != ymd_trial.year())  
7739 - goto broken;  
7740 - if (m == not_a_month)  
7741 - m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));  
7742 - else if (month(static_cast<unsigned>(m)) != ymd_trial.month())  
7743 - goto broken;  
7744 - if (d == not_a_day)  
7745 - d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));  
7746 - else if (day(static_cast<unsigned>(d)) != ymd_trial.day())  
7747 - goto broken;  
7748 - computed = true;  
7749 - }  
7750 - if (Y != not_a_year && W != not_a_week_num && wd != not_a_weekday)  
7751 - {  
7752 - year_month_day ymd_trial = sys_days(year{Y}/January/Monday[1]) +  
7753 - weeks{W-1} +  
7754 - (weekday{static_cast<unsigned>(wd)} - Monday);  
7755 - if (Y == not_a_year)  
7756 - Y = static_cast<int>(ymd_trial.year());  
7757 - else if (year{Y} != ymd_trial.year())  
7758 - goto broken;  
7759 - if (m == not_a_month)  
7760 - m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));  
7761 - else if (month(static_cast<unsigned>(m)) != ymd_trial.month())  
7762 - goto broken;  
7763 - if (d == not_a_day)  
7764 - d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));  
7765 - else if (day(static_cast<unsigned>(d)) != ymd_trial.day())  
7766 - goto broken;  
7767 - computed = true;  
7768 - }  
7769 - if (j != not_a_doy && Y != not_a_year)  
7770 - {  
7771 - auto ymd_trial = year_month_day{local_days(year{Y}/1/1) + days{j-1}};  
7772 - if (m == not_a_month)  
7773 - m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));  
7774 - else if (month(static_cast<unsigned>(m)) != ymd_trial.month())  
7775 - goto broken;  
7776 - if (d == not_a_day)  
7777 - d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));  
7778 - else if (day(static_cast<unsigned>(d)) != ymd_trial.day())  
7779 - goto broken;  
7780 - j = not_a_doy;  
7781 - }  
7782 - auto ymd = year{Y}/m/d;  
7783 - if (ymd.ok())  
7784 - {  
7785 - if (wd == not_a_weekday)  
7786 - wd = static_cast<int>((weekday(sys_days(ymd)) - Sunday).count());  
7787 - else if (wd != static_cast<int>((weekday(sys_days(ymd)) - Sunday).count()))  
7788 - goto broken;  
7789 - if (!computed)  
7790 - {  
7791 - if (G != not_a_year || V != not_a_week_num)  
7792 - {  
7793 - sys_days sd = ymd;  
7794 - auto G_trial = year_month_day{sd + days{3}}.year();  
7795 - auto start = sys_days((G_trial - years{1})/December/Thursday[last]) +  
7796 - (Monday - Thursday);  
7797 - if (sd < start)  
7798 - {  
7799 - --G_trial;  
7800 - if (V != not_a_week_num)  
7801 - start = sys_days((G_trial - years{1})/December/Thursday[last])  
7802 - + (Monday - Thursday);  
7803 - }  
7804 - if (G != not_a_year && G != static_cast<int>(G_trial))  
7805 - goto broken;  
7806 - if (V != not_a_week_num)  
7807 - {  
7808 - auto V_trial = duration_cast<weeks>(sd - start).count() + 1;  
7809 - if (V != V_trial)  
7810 - goto broken;  
7811 - }  
7812 - }  
7813 - if (U != not_a_week_num)  
7814 - {  
7815 - auto start = sys_days(Sunday[1]/January/ymd.year());  
7816 - auto U_trial = floor<weeks>(sys_days(ymd) - start).count() + 1;  
7817 - if (U != U_trial)  
7818 - goto broken;  
7819 - }  
7820 - if (W != not_a_week_num)  
7821 - {  
7822 - auto start = sys_days(Monday[1]/January/ymd.year());  
7823 - auto W_trial = floor<weeks>(sys_days(ymd) - start).count() + 1;  
7824 - if (W != W_trial)  
7825 - goto broken;  
7826 - }  
7827 - }  
7828 - }  
7829 - fds.ymd = ymd;  
7830 - if (I != not_a_hour_12_value)  
7831 - {  
7832 - if (!(1 <= I && I <= 12))  
7833 - goto broken;  
7834 - if (p != not_a_ampm)  
7835 - {  
7836 - // p is in [0, 1] == [AM, PM]  
7837 - // Store trial H in I  
7838 - if (I == 12)  
7839 - --p;  
7840 - I += p*12;  
7841 - // Either set H from I or make sure H and I are consistent  
7842 - if (H == not_a_hour)  
7843 - H = I;  
7844 - else if (I != H)  
7845 - goto broken;  
7846 - }  
7847 - else // p == not_a_ampm  
7848 - {  
7849 - // if H, make sure H and I could be consistent  
7850 - if (H != not_a_hour)  
7851 - {  
7852 - if (I == 12)  
7853 - {  
7854 - if (H != 0 && H != 12)  
7855 - goto broken;  
7856 - }  
7857 - else if (!(I == H || I == H+12))  
7858 - {  
7859 - goto broken;  
7860 - }  
7861 - }  
7862 - else // I is ambiguous, AM or PM?  
7863 - goto broken;  
7864 - }  
7865 - }  
7866 - if (H != not_a_hour)  
7867 - {  
7868 - fds.has_tod = true;  
7869 - fds.tod = hh_mm_ss<Duration>{hours{H}};  
7870 - }  
7871 - if (M != not_a_minute)  
7872 - {  
7873 - fds.has_tod = true;  
7874 - fds.tod.m_ = minutes{M};  
7875 - }  
7876 - if (s != not_a_second)  
7877 - {  
7878 - fds.has_tod = true;  
7879 - fds.tod.s_ = detail::decimal_format_seconds<Duration>{s};  
7880 - }  
7881 - if (j != not_a_doy)  
7882 - {  
7883 - fds.has_tod = true;  
7884 - fds.tod.h_ += hours{days{j}};  
7885 - }  
7886 - if (wd != not_a_weekday)  
7887 - fds.wd = weekday{static_cast<unsigned>(wd)};  
7888 - if (abbrev != nullptr)  
7889 - *abbrev = std::move(temp_abbrev);  
7890 - if (offset != nullptr && temp_offset != not_a_offset)  
7891 - *offset = temp_offset;  
7892 - }  
7893 - return is;  
7894 - }  
7895 -broken:  
7896 - is.setstate(ios::failbit);  
7897 - return is;  
7898 -}  
7899 -  
7900 -template <class CharT, class Traits, class Alloc = std::allocator<CharT>>  
7901 -std::basic_istream<CharT, Traits>&  
7902 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, year& y,  
7903 - std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
7904 - std::chrono::minutes* offset = nullptr)  
7905 -{  
7906 - using CT = std::chrono::seconds;  
7907 - fields<CT> fds{};  
7908 - date::from_stream(is, fmt, fds, abbrev, offset);  
7909 - if (!fds.ymd.year().ok())  
7910 - is.setstate(std::ios::failbit);  
7911 - if (!is.fail())  
7912 - y = fds.ymd.year();  
7913 - return is;  
7914 -}  
7915 -  
7916 -template <class CharT, class Traits, class Alloc = std::allocator<CharT>>  
7917 -std::basic_istream<CharT, Traits>&  
7918 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, month& m,  
7919 - std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
7920 - std::chrono::minutes* offset = nullptr)  
7921 -{  
7922 - using CT = std::chrono::seconds;  
7923 - fields<CT> fds{};  
7924 - date::from_stream(is, fmt, fds, abbrev, offset);  
7925 - if (!fds.ymd.month().ok())  
7926 - is.setstate(std::ios::failbit);  
7927 - if (!is.fail())  
7928 - m = fds.ymd.month();  
7929 - return is;  
7930 -}  
7931 -  
7932 -template <class CharT, class Traits, class Alloc = std::allocator<CharT>>  
7933 -std::basic_istream<CharT, Traits>&  
7934 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, day& d,  
7935 - std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
7936 - std::chrono::minutes* offset = nullptr)  
7937 -{  
7938 - using CT = std::chrono::seconds;  
7939 - fields<CT> fds{};  
7940 - date::from_stream(is, fmt, fds, abbrev, offset);  
7941 - if (!fds.ymd.day().ok())  
7942 - is.setstate(std::ios::failbit);  
7943 - if (!is.fail())  
7944 - d = fds.ymd.day();  
7945 - return is;  
7946 -}  
7947 -  
7948 -template <class CharT, class Traits, class Alloc = std::allocator<CharT>>  
7949 -std::basic_istream<CharT, Traits>&  
7950 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, weekday& wd,  
7951 - std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
7952 - std::chrono::minutes* offset = nullptr)  
7953 -{  
7954 - using CT = std::chrono::seconds;  
7955 - fields<CT> fds{};  
7956 - date::from_stream(is, fmt, fds, abbrev, offset);  
7957 - if (!fds.wd.ok())  
7958 - is.setstate(std::ios::failbit);  
7959 - if (!is.fail())  
7960 - wd = fds.wd;  
7961 - return is;  
7962 -}  
7963 -  
7964 -template <class CharT, class Traits, class Alloc = std::allocator<CharT>>  
7965 -std::basic_istream<CharT, Traits>&  
7966 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, year_month& ym,  
7967 - std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
7968 - std::chrono::minutes* offset = nullptr)  
7969 -{  
7970 - using CT = std::chrono::seconds;  
7971 - fields<CT> fds{};  
7972 - date::from_stream(is, fmt, fds, abbrev, offset);  
7973 - if (!fds.ymd.month().ok())  
7974 - is.setstate(std::ios::failbit);  
7975 - if (!is.fail())  
7976 - ym = fds.ymd.year()/fds.ymd.month();  
7977 - return is;  
7978 -}  
7979 -  
7980 -template <class CharT, class Traits, class Alloc = std::allocator<CharT>>  
7981 -std::basic_istream<CharT, Traits>&  
7982 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, month_day& md,  
7983 - std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
7984 - std::chrono::minutes* offset = nullptr)  
7985 -{  
7986 - using CT = std::chrono::seconds;  
7987 - fields<CT> fds{};  
7988 - date::from_stream(is, fmt, fds, abbrev, offset);  
7989 - if (!fds.ymd.month().ok() || !fds.ymd.day().ok())  
7990 - is.setstate(std::ios::failbit);  
7991 - if (!is.fail())  
7992 - md = fds.ymd.month()/fds.ymd.day();  
7993 - return is;  
7994 -}  
7995 -  
7996 -template <class CharT, class Traits, class Alloc = std::allocator<CharT>>  
7997 -std::basic_istream<CharT, Traits>&  
7998 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,  
7999 - year_month_day& ymd, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
8000 - std::chrono::minutes* offset = nullptr)  
8001 -{  
8002 - using CT = std::chrono::seconds;  
8003 - fields<CT> fds{};  
8004 - date::from_stream(is, fmt, fds, abbrev, offset);  
8005 - if (!fds.ymd.ok())  
8006 - is.setstate(std::ios::failbit);  
8007 - if (!is.fail())  
8008 - ymd = fds.ymd;  
8009 - return is;  
8010 -}  
8011 -  
8012 -template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>  
8013 -std::basic_istream<CharT, Traits>&  
8014 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,  
8015 - sys_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
8016 - std::chrono::minutes* offset = nullptr)  
8017 -{  
8018 - using CT = typename std::common_type<Duration, std::chrono::seconds>::type;  
8019 - using detail::round_i;  
8020 - std::chrono::minutes offset_local{};  
8021 - auto offptr = offset ? offset : &offset_local;  
8022 - fields<CT> fds{};  
8023 - fds.has_tod = true;  
8024 - date::from_stream(is, fmt, fds, abbrev, offptr);  
8025 - if (!fds.ymd.ok() || !fds.tod.in_conventional_range())  
8026 - is.setstate(std::ios::failbit);  
8027 - if (!is.fail())  
8028 - tp = round_i<Duration>(sys_days(fds.ymd) - *offptr + fds.tod.to_duration());  
8029 - return is;  
8030 -}  
8031 -  
8032 -template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>  
8033 -std::basic_istream<CharT, Traits>&  
8034 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,  
8035 - local_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
8036 - std::chrono::minutes* offset = nullptr)  
8037 -{  
8038 - using CT = typename std::common_type<Duration, std::chrono::seconds>::type;  
8039 - using detail::round_i;  
8040 - fields<CT> fds{};  
8041 - fds.has_tod = true;  
8042 - date::from_stream(is, fmt, fds, abbrev, offset);  
8043 - if (!fds.ymd.ok() || !fds.tod.in_conventional_range())  
8044 - is.setstate(std::ios::failbit);  
8045 - if (!is.fail())  
8046 - tp = round_i<Duration>(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration());  
8047 - return is;  
8048 -}  
8049 -  
8050 -template <class Rep, class Period, class CharT, class Traits, class Alloc = std::allocator<CharT>>  
8051 -std::basic_istream<CharT, Traits>&  
8052 -from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,  
8053 - std::chrono::duration<Rep, Period>& d,  
8054 - std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
8055 - std::chrono::minutes* offset = nullptr)  
8056 -{  
8057 - using Duration = std::chrono::duration<Rep, Period>;  
8058 - using CT = typename std::common_type<Duration, std::chrono::seconds>::type;  
8059 - using detail::round_i;  
8060 - fields<CT> fds{};  
8061 - date::from_stream(is, fmt, fds, abbrev, offset);  
8062 - if (!fds.has_tod)  
8063 - is.setstate(std::ios::failbit);  
8064 - if (!is.fail())  
8065 - d = round_i<Duration>(fds.tod.to_duration());  
8066 - return is;  
8067 -}  
8068 -  
8069 -template <class Parsable, class CharT, class Traits = std::char_traits<CharT>,  
8070 - class Alloc = std::allocator<CharT>>  
8071 -struct parse_manip  
8072 -{  
8073 - const std::basic_string<CharT, Traits, Alloc> format_;  
8074 - Parsable& tp_;  
8075 - std::basic_string<CharT, Traits, Alloc>* abbrev_;  
8076 - std::chrono::minutes* offset_;  
8077 -  
8078 -public:  
8079 - parse_manip(std::basic_string<CharT, Traits, Alloc> format, Parsable& tp,  
8080 - std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
8081 - std::chrono::minutes* offset = nullptr)  
8082 - : format_(std::move(format))  
8083 - , tp_(tp)  
8084 - , abbrev_(abbrev)  
8085 - , offset_(offset)  
8086 - {}  
8087 -  
8088 -#if HAS_STRING_VIEW  
8089 - parse_manip(const CharT* format, Parsable& tp,  
8090 - std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
8091 - std::chrono::minutes* offset = nullptr)  
8092 - : format_(format)  
8093 - , tp_(tp)  
8094 - , abbrev_(abbrev)  
8095 - , offset_(offset)  
8096 - {}  
8097 -  
8098 - parse_manip(std::basic_string_view<CharT, Traits> format, Parsable& tp,  
8099 - std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,  
8100 - std::chrono::minutes* offset = nullptr)  
8101 - : format_(format)  
8102 - , tp_(tp)  
8103 - , abbrev_(abbrev)  
8104 - , offset_(offset)  
8105 - {}  
8106 -#endif // HAS_STRING_VIEW  
8107 -};  
8108 -  
8109 -template <class Parsable, class CharT, class Traits, class Alloc>  
8110 -std::basic_istream<CharT, Traits>&  
8111 -operator>>(std::basic_istream<CharT, Traits>& is,  
8112 - const parse_manip<Parsable, CharT, Traits, Alloc>& x)  
8113 -{  
8114 - return date::from_stream(is, x.format_.c_str(), x.tp_, x.abbrev_, x.offset_);  
8115 -}  
8116 -  
8117 -template <class Parsable, class CharT, class Traits, class Alloc>  
8118 -inline  
8119 -auto  
8120 -parse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp)  
8121 - -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),  
8122 - format.c_str(), tp),  
8123 - parse_manip<Parsable, CharT, Traits, Alloc>{format, tp})  
8124 -{  
8125 - return {format, tp};  
8126 -}  
8127 -  
8128 -template <class Parsable, class CharT, class Traits, class Alloc>  
8129 -inline  
8130 -auto  
8131 -parse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp,  
8132 - std::basic_string<CharT, Traits, Alloc>& abbrev)  
8133 - -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),  
8134 - format.c_str(), tp, &abbrev),  
8135 - parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev})  
8136 -{  
8137 - return {format, tp, &abbrev};  
8138 -}  
8139 -  
8140 -template <class Parsable, class CharT, class Traits, class Alloc>  
8141 -inline  
8142 -auto  
8143 -parse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp,  
8144 - std::chrono::minutes& offset)  
8145 - -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),  
8146 - format.c_str(), tp,  
8147 - std::declval<std::basic_string<CharT, Traits, Alloc>*>(),  
8148 - &offset),  
8149 - parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, nullptr, &offset})  
8150 -{  
8151 - return {format, tp, nullptr, &offset};  
8152 -}  
8153 -  
8154 -template <class Parsable, class CharT, class Traits, class Alloc>  
8155 -inline  
8156 -auto  
8157 -parse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp,  
8158 - std::basic_string<CharT, Traits, Alloc>& abbrev, std::chrono::minutes& offset)  
8159 - -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),  
8160 - format.c_str(), tp, &abbrev, &offset),  
8161 - parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev, &offset})  
8162 -{  
8163 - return {format, tp, &abbrev, &offset};  
8164 -}  
8165 -  
8166 -// const CharT* formats  
8167 -  
8168 -template <class Parsable, class CharT>  
8169 -inline  
8170 -auto  
8171 -parse(const CharT* format, Parsable& tp)  
8172 - -> decltype(date::from_stream(std::declval<std::basic_istream<CharT>&>(), format, tp),  
8173 - parse_manip<Parsable, CharT>{format, tp})  
8174 -{  
8175 - return {format, tp};  
8176 -}  
8177 -  
8178 -template <class Parsable, class CharT, class Traits, class Alloc>  
8179 -inline  
8180 -auto  
8181 -parse(const CharT* format, Parsable& tp, std::basic_string<CharT, Traits, Alloc>& abbrev)  
8182 - -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(), format,  
8183 - tp, &abbrev),  
8184 - parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev})  
8185 -{  
8186 - return {format, tp, &abbrev};  
8187 -}  
8188 -  
8189 -template <class Parsable, class CharT>  
8190 -inline  
8191 -auto  
8192 -parse(const CharT* format, Parsable& tp, std::chrono::minutes& offset)  
8193 - -> decltype(date::from_stream(std::declval<std::basic_istream<CharT>&>(), format,  
8194 - tp, std::declval<std::basic_string<CharT>*>(), &offset),  
8195 - parse_manip<Parsable, CharT>{format, tp, nullptr, &offset})  
8196 -{  
8197 - return {format, tp, nullptr, &offset};  
8198 -}  
8199 -  
8200 -template <class Parsable, class CharT, class Traits, class Alloc>  
8201 -inline  
8202 -auto  
8203 -parse(const CharT* format, Parsable& tp,  
8204 - std::basic_string<CharT, Traits, Alloc>& abbrev, std::chrono::minutes& offset)  
8205 - -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(), format,  
8206 - tp, &abbrev, &offset),  
8207 - parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev, &offset})  
8208 -{  
8209 - return {format, tp, &abbrev, &offset};  
8210 -}  
8211 -  
8212 -// duration streaming  
8213 -  
8214 -template <class CharT, class Traits, class Rep, class Period>  
8215 -inline  
8216 -std::basic_ostream<CharT, Traits>&  
8217 -operator<<(std::basic_ostream<CharT, Traits>& os,  
8218 - const std::chrono::duration<Rep, Period>& d)  
8219 -{  
8220 - return os << detail::make_string<CharT, Traits>::from(d.count()) +  
8221 - detail::get_units<CharT>(typename Period::type{});  
8222 -}  
8223 -  
8224 -} // namespace date  
8225 -  
8226 -#ifdef _MSC_VER  
8227 -# pragma warning(pop)  
8228 -#endif  
8229 -  
8230 -#ifdef __GNUC__  
8231 -# pragma GCC diagnostic pop  
8232 -#endif  
8233 -  
8234 -#endif // DATE_H  
8235 -  
src/errorcode.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_ERRORCODE_H  
23 -#define OSDEV_COMPONENTS_MQTT_ERRORCODE_H  
24 -  
25 -// std  
26 -#include <string>  
27 -  
28 -namespace osdev {  
29 -namespace components {  
30 -namespace mqtt {  
31 -  
32 -/*!  
33 - * \return A stringified paho error code...  
34 - */  
35 -std::string pahoAsyncErrorCodeToString( int errorCode );  
36 -  
37 -  
38 -} // End namespace mqtt  
39 -} // End nnamespace components  
40 -} // End namesapce osdev  
41 -  
42 -#endif // OSDEV_COMPONENTS_MQTT_ERRORCODE_H  
src/histogram.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MEASUREMENT_HISTOGRAM_H  
23 -#define OSDEV_COMPONENTS_MQTT_MEASUREMENT_HISTOGRAM_H  
24 -  
25 -#include <atomic>  
26 -#include <cmath>  
27 -#include <limits>  
28 -#include <mutex>  
29 -#include <string>  
30 -#include <vector>  
31 -  
32 -#include "utils.h"  
33 -  
34 -#include "ihistogram.h"  
35 -  
36 -namespace osdev {  
37 -namespace components {  
38 -namespace mqtt {  
39 -namespace measurement {  
40 -  
41 -template <typename T>  
42 -double fabs(T val)  
43 -{  
44 - return std::fabs(val);  
45 -}  
46 -  
47 -template <typename Rep, typename Dur>  
48 -double fabs(const std::chrono::duration<Rep, Dur>& dur)  
49 -{  
50 - return std::fabs(dur.count());  
51 -}  
52 -  
53 -template <typename T>  
54 -double to_double(T val)  
55 -{  
56 - return static_cast<double>(val);  
57 -}  
58 -  
59 -template <typename Rep, typename Dur>  
60 -double to_double(const std::chrono::duration<Rep, Dur>& dur)  
61 -{  
62 - return static_cast<double>(dur.count());  
63 -}  
64 -  
65 -template <typename T>  
66 -std::string to_string(T val)  
67 -{  
68 - return std::to_string(val);  
69 -}  
70 -  
71 -template <typename Rep, typename Dur>  
72 -std::string to_string(const std::chrono::duration<Rep, Dur>& dur)  
73 -{  
74 - return std::to_string(dur.count());  
75 -}  
76 -  
77 -template <typename T>  
78 -T min(T)  
79 -{  
80 - return std::numeric_limits<T>::min();  
81 -}  
82 -  
83 -template <typename Rep, typename Dur>  
84 -std::chrono::duration<Rep, Dur> min(const std::chrono::duration<Rep, Dur>&)  
85 -{  
86 - return std::chrono::duration<Rep, Dur>::min();  
87 -}  
88 -  
89 -template <typename T>  
90 -T max(T)  
91 -{  
92 - return std::numeric_limits<T>::max();  
93 -}  
94 -  
95 -template <typename Rep, typename Dur>  
96 -std::chrono::duration<Rep, Dur> max(const std::chrono::duration<Rep, Dur>&)  
97 -{  
98 - return std::chrono::duration<Rep, Dur>::max();  
99 -}  
100 -  
101 -/**  
102 - * @brief This class implements a histogram for typed values.  
103 - * Outlier values to the left are counted on the first bin and to the right on the last bin.  
104 - * @tparam T The value type. T must be default constructable.  
105 - * @tparam Buckets The number of buckets to use for this histogram. Default is 10 buckets.  
106 - */  
107 -template <typename T, std::size_t Buckets = 10>  
108 -class Histogram : public IHistogram  
109 -{  
110 -public:  
111 - /**  
112 - * @brief Construct a histogram.  
113 - * @param id The histogram identification  
114 - * @param minValue The minimum value of the histogram.  
115 - * @param maxValue The maxmim value of the histogram.  
116 - * @param unit The unit of the values that are collected in this histogram.  
117 - */  
118 - Histogram(const std::string& id, T minValue, T maxValue, const char* unit);  
119 -  
120 - /**  
121 - * @brief Set a value in the histogram.  
122 - */  
123 - void setValue(T value);  
124 -  
125 - /**  
126 - * @return true when values are added since the last time a snapshot was taken of the histogram or a reset was performed, false otherwise.  
127 - */  
128 - bool isUpdated() const;  
129 -  
130 - /**  
131 - * @brief Reset the histogram.  
132 - * All counts are made zero and the smallest and largest recorded values are set to default.  
133 - */  
134 - void reset();  
135 -  
136 - // IHistogram implementation  
137 - virtual const std::string& id() const override;  
138 - virtual std::size_t numBuckets() const override;  
139 - virtual double bucketWidth() const override;  
140 - virtual std::string minValueString() const override;  
141 - virtual std::string maxValueString() const override;  
142 - virtual const std::string& unit() const override;  
143 - virtual HistogramData histogramData() const override;  
144 - virtual std::size_t numberOfValuesSinceLastClear() const override;  
145 - virtual std::string smallestValueSinceLastClear() const override;  
146 - virtual std::string largestValueSinceLastClear() const override;  
147 - virtual std::string averageValueSinceLastClear() const override;  
148 - virtual void clearRunningValues() override;  
149 - virtual std::string toString() const override;  
150 -  
151 -private:  
152 - /**  
153 - * @brief Get the index on which to count the given value.  
154 - * The outliers to the left are counted on index 0 and to the right on index size() - 1.  
155 - * @param value The value to get the index for.  
156 - * @return the index in the histogram on which to count the given value.  
157 - */  
158 - inline std::size_t index(T value)  
159 - {  
160 - if (value > m_maxValue) {  
161 - return m_histogram.size() - 1;  
162 - }  
163 - if (value < m_minValue) {  
164 - return 0;  
165 - }  
166 -  
167 - return 1 + static_cast<std::size_t>(to_double((value - m_minValue) / m_bucketWidth));  
168 - }  
169 -  
170 - const std::string m_id;  
171 - const std::string m_unit;  
172 - const T m_minValue;  
173 - const T m_maxValue;  
174 - const double m_bucketWidth;  
175 - T m_smallestValue;  
176 - T m_largestValue;  
177 - T m_smallestValueSinceLastClear;  
178 - T m_largestValueSinceLastClear;  
179 - T m_summedValueSinceLastClear;  
180 - std::size_t m_numberOfValuesSinceLastClear;  
181 - mutable std::mutex m_mutex;  
182 - std::vector<std::size_t> m_histogram;  
183 - mutable std::atomic_bool m_isUpdated;  
184 -};  
185 -  
186 -template <typename T, std::size_t Buckets>  
187 -Histogram<T, Buckets>::Histogram(const std::string& _id, T minValue, T maxValue, const char* _unit)  
188 - : m_id(_id)  
189 - , m_unit(_unit)  
190 - , m_minValue(minValue)  
191 - , m_maxValue(maxValue)  
192 - , m_bucketWidth(fabs((m_maxValue - m_minValue)) / Buckets)  
193 - , m_smallestValue{ max(maxValue) }  
194 - , m_largestValue{ min(maxValue) }  
195 - , m_smallestValueSinceLastClear{ max(maxValue) }  
196 - , m_largestValueSinceLastClear{ min(maxValue) }  
197 - , m_summedValueSinceLastClear{}  
198 - , m_numberOfValuesSinceLastClear{}  
199 - , m_mutex()  
200 - , m_histogram(Buckets + 2) // + 2 for the out of bound buckets  
201 - , m_isUpdated(false)  
202 -{  
203 -}  
204 -  
205 -template <typename T, std::size_t Buckets>  
206 -void Histogram<T, Buckets>::setValue(T value)  
207 -{  
208 - std::lock_guard<std::mutex> lg(m_mutex);  
209 - apply_unused_parameters(lg);  
210 -  
211 - if (value > m_largestValueSinceLastClear) {  
212 - m_largestValueSinceLastClear = value;  
213 - }  
214 -  
215 - if (value < m_smallestValueSinceLastClear) {  
216 - m_smallestValueSinceLastClear = value;  
217 - }  
218 -  
219 - if (value > m_largestValue) {  
220 - m_largestValue = value;  
221 - }  
222 -  
223 - if (value < m_smallestValue) {  
224 - m_smallestValue = value;  
225 - }  
226 -  
227 - m_summedValueSinceLastClear += value;  
228 - ++m_numberOfValuesSinceLastClear;  
229 -  
230 - m_histogram[this->index(value)]++;  
231 - m_isUpdated = true;  
232 -}  
233 -  
234 -template <typename T, std::size_t Buckets>  
235 -bool Histogram<T, Buckets>::isUpdated() const  
236 -{  
237 - return m_isUpdated;  
238 -}  
239 -  
240 -template <typename T, std::size_t Buckets>  
241 -void Histogram<T, Buckets>::reset()  
242 -{  
243 - std::lock_guard<std::mutex> lg(m_mutex);  
244 - apply_unused_parameters(lg);  
245 -  
246 - m_smallestValue = T{ max(m_maxValue) };  
247 - m_largestValue = T{ min(m_maxValue) };  
248 - m_smallestValueSinceLastClear = T{ max(m_maxValue) };  
249 - m_largestValueSinceLastClear = T{ min(m_maxValue) };  
250 - m_summedValueSinceLastClear = T{};  
251 - m_numberOfValuesSinceLastClear = 0;  
252 -  
253 - std::fill(m_histogram.begin(), m_histogram.end(), 0);  
254 - m_isUpdated = false;  
255 -}  
256 -  
257 -template <typename T, std::size_t Buckets>  
258 -const std::string& Histogram<T, Buckets>::id() const  
259 -{  
260 - return m_id;  
261 -}  
262 -  
263 -template <typename T, std::size_t Buckets>  
264 -std::size_t Histogram<T, Buckets>::numBuckets() const  
265 -{  
266 - return Buckets;  
267 -}  
268 -  
269 -template <typename T, std::size_t Buckets>  
270 -double Histogram<T, Buckets>::bucketWidth() const  
271 -{  
272 - return m_bucketWidth;  
273 -}  
274 -  
275 -template <typename T, std::size_t Buckets>  
276 -std::string Histogram<T, Buckets>::minValueString() const  
277 -{  
278 - return to_string(m_minValue);  
279 -}  
280 -  
281 -template <typename T, std::size_t Buckets>  
282 -std::string Histogram<T, Buckets>::maxValueString() const  
283 -{  
284 - return to_string(m_maxValue);  
285 -}  
286 -  
287 -template <typename T, std::size_t Buckets>  
288 -const std::string& Histogram<T, Buckets>::unit() const  
289 -{  
290 - return m_unit;  
291 -}  
292 -  
293 -template <typename T, std::size_t Buckets>  
294 -HistogramData Histogram<T, Buckets>::histogramData() const  
295 -{  
296 - std::lock_guard<std::mutex> lg(m_mutex);  
297 - apply_unused_parameters(lg);  
298 -  
299 - m_isUpdated = false;  
300 - return HistogramData(to_string(m_smallestValue), to_string(m_largestValue),  
301 - to_string(m_smallestValueSinceLastClear), to_string(m_largestValueSinceLastClear), averageValueSinceLastClear(),  
302 - m_numberOfValuesSinceLastClear, m_histogram);  
303 -}  
304 -  
305 -template <typename T, std::size_t Buckets>  
306 -std::size_t Histogram<T, Buckets>::numberOfValuesSinceLastClear() const  
307 -{  
308 - return m_numberOfValuesSinceLastClear;  
309 -}  
310 -  
311 -template <typename T, std::size_t Buckets>  
312 -std::string Histogram<T, Buckets>::smallestValueSinceLastClear() const  
313 -{  
314 - return to_string(m_smallestValueSinceLastClear);  
315 -}  
316 -  
317 -template <typename T, std::size_t Buckets>  
318 -std::string Histogram<T, Buckets>::largestValueSinceLastClear() const  
319 -{  
320 - return to_string(m_largestValueSinceLastClear);  
321 -}  
322 -  
323 -template <typename T, std::size_t Buckets>  
324 -std::string Histogram<T, Buckets>::averageValueSinceLastClear() const  
325 -{  
326 - if (0 == m_numberOfValuesSinceLastClear) {  
327 - return "undefined";  
328 - }  
329 - return to_string(to_double(m_summedValueSinceLastClear) / m_numberOfValuesSinceLastClear);  
330 -}  
331 -  
332 -template <typename T, std::size_t Buckets>  
333 -void Histogram<T, Buckets>::clearRunningValues()  
334 -{  
335 - std::lock_guard<std::mutex> lg(m_mutex);  
336 - apply_unused_parameters(lg);  
337 -  
338 - m_smallestValueSinceLastClear = T{ max(m_maxValue) };  
339 - m_largestValueSinceLastClear = T{ min(m_maxValue) };  
340 - m_summedValueSinceLastClear = T{};  
341 - m_numberOfValuesSinceLastClear = 0;  
342 -}  
343 -  
344 -template <typename T, std::size_t Buckets>  
345 -std::string Histogram<T, Buckets>::toString() const  
346 -{  
347 - return visualizeHistogram(*this);  
348 -}  
349 -  
350 -} // End namespace measurement  
351 -} // End namespace mqtt  
352 -} // End namespace components  
353 -} // End namespace osdev  
354 -  
355 -#endif // OSDEV_COMPONENTS_MQTT_MEASUREMENT_HISTOGRAM_H  
src/histogramprovider.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MEASUREMENT_HISTOGRAMPROVIDER_H  
23 -#define OSDEV_COMPONENTS_MQTT_MEASUREMENT_HISTOGRAMPROVIDER_H  
24 -  
25 -// std  
26 -#include <iostream>  
27 -#include <memory>  
28 -#include <string>  
29 -#include <unordered_map>  
30 -  
31 -#include "compat-c++14.h"  
32 -  
33 -// mlogic::common  
34 -#include "sharedreaderlock.h"  
35 -  
36 -#include "histogram.h"  
37 -  
38 -namespace osdev {  
39 -namespace components {  
40 -namespace mqtt {  
41 -namespace measurement {  
42 -  
43 -/**  
44 - * @brief This class provides the user with Entry class for putting measurements in a histogram.  
45 - * @tparam TContext A tag type that is used to give the HistogramProvider a user defined context.  
46 - * @tparam TValue Defines the value type that the histograms of this provider use.  
47 - * @tparam Buckets The number of buckets to use on creation of a Histogram. The default number of buckets is 10.  
48 - *  
49 - * The TValue type must define the following publically visible members.  
50 - *  
51 - * value_type - The underlying value type used in the histogram  
52 - * const value_type minValue - The minimum value of the histogram  
53 - * const value_type maxValue - The maximum value of the histogram  
54 - * const char* unit - The value unit.  
55 - */  
56 -template <typename TContext, typename TValue, std::size_t Buckets = 10>  
57 -class HistogramProvider  
58 -{  
59 -public:  
60 - using HistogramType = Histogram<typename TValue::value_type, Buckets>;  
61 -  
62 - /**  
63 - * @brief Get the HistogramProvider instance.  
64 - */  
65 - static HistogramProvider& instance();  
66 -  
67 - /**  
68 - * @brief Add a value to the histogram identified by id.  
69 - * @param id Identifies the histogram to add the value to.  
70 - * @param value The value to add.  
71 - */  
72 - void addValue(const std::string& id, typename TValue::value_type value);  
73 -  
74 - /**  
75 - * @brief Log the histogram identified by id via the ILogger framework.  
76 - * @param id The histogram to log. If no histogram is found no work is done.  
77 - */  
78 - void log(const std::string& id);  
79 -  
80 - /**  
81 - * @brief Log the histograms via the ILogger framework.  
82 - * @param onlyChanged When set to true only log histograms that have changed. Default is false.  
83 - */  
84 - void logAll(bool onlyChanged = false);  
85 -  
86 - /**  
87 - * @brief Reset all the histograms.  
88 - * @param logBeforeReset Flag that indicates whether the histogram needs to be logged before reset. Default is true.  
89 - * @note Only changed histograms are logged.  
90 - */  
91 - void resetAll(bool logBeforeReset = true);  
92 -  
93 - /**  
94 - * @return The logOnDestroy flag value.  
95 - */  
96 - bool logOnDestroy() const { return m_logOnDestroy; }  
97 -  
98 - /**  
99 - * @brief Set the logOnDestroy flag.  
100 - * @param logOnDest Log on destruction when true, do not log when set to false.  
101 - */  
102 - void setLogOnDestroy(bool logOnDest) { m_logOnDestroy = logOnDest; }  
103 -  
104 -private:  
105 - HistogramProvider();  
106 -  
107 - /**  
108 - * @brief On destruction the provider will log all its histogram information to stdout.  
109 - * Since the destruction will happen as one of the last things in the process, stdout is  
110 - * used for logging.  
111 - */  
112 - ~HistogramProvider();  
113 -  
114 - void log(const HistogramType& hist, bool onlyChanged);  
115 -  
116 - SharedReaderLock m_sharedLock;  
117 - std::unordered_map<std::string, std::unique_ptr<HistogramType>> m_histograms;  
118 - bool m_logOnDestroy; ///< Default is true.  
119 -};  
120 -  
121 -// static  
122 -template <typename TContext, typename TValue, std::size_t Buckets>  
123 -HistogramProvider<TContext, TValue, Buckets>& HistogramProvider<TContext, TValue, Buckets>::instance()  
124 -{  
125 - static HistogramProvider<TContext, TValue, Buckets> s_provider;  
126 - return s_provider;  
127 -}  
128 -  
129 -template <typename TContext, typename TValue, std::size_t Buckets>  
130 -void HistogramProvider<TContext, TValue, Buckets>::addValue(const std::string& id, typename TValue::value_type value)  
131 -{  
132 - OSDEV_COMPONENTS_SHAREDLOCK_SCOPE(m_sharedLock);  
133 - auto it = m_histograms.find(id);  
134 - if (m_histograms.end() == it) {  
135 - OSDEV_COMPONENTS_EXCLUSIVELOCK_SCOPE(m_sharedLock);  
136 - constexpr TValue val;  
137 - it = (m_histograms.emplace(std::make_pair(id, std::make_unique<HistogramType>(id, val.minValue, val.maxValue, val.unit)))).first;  
138 - }  
139 - it->second->setValue(value);  
140 -}  
141 -  
142 -template <typename TContext, typename TValue, std::size_t Buckets>  
143 -void HistogramProvider<TContext, TValue, Buckets>::log(const std::string& id)  
144 -{  
145 - OSDEV_COMPONENTS_SHAREDLOCK_SCOPE(m_sharedLock);  
146 - auto it = m_histograms.find(id);  
147 - if (m_histograms.end() != it) {  
148 - log(*(it->second), false);  
149 - }  
150 -}  
151 -  
152 -template <typename TContext, typename TValue, std::size_t Buckets>  
153 -void HistogramProvider<TContext, TValue, Buckets>::logAll(bool onlyChanged)  
154 -{  
155 - OSDEV_COMPONENTS_SHAREDLOCK_SCOPE(m_sharedLock);  
156 - for (const auto& h : m_histograms) {  
157 - log(*h.second, onlyChanged);  
158 - }  
159 -}  
160 -  
161 -template <typename TContext, typename TValue, std::size_t Buckets>  
162 -void HistogramProvider<TContext, TValue, Buckets>::resetAll(bool logBeforeReset)  
163 -{  
164 - OSDEV_COMPONENTS_SHAREDLOCK_SCOPE(m_sharedLock);  
165 - for (const auto& h : m_histograms) {  
166 - if (logBeforeReset) {  
167 - log(*h.second, true); // only log the histograms that have changed  
168 - }  
169 - h.second->reset();  
170 - }  
171 -}  
172 -  
173 -template <typename TContext, typename TValue, std::size_t Buckets>  
174 -HistogramProvider<TContext, TValue, Buckets>::HistogramProvider()  
175 - : m_sharedLock()  
176 - , m_histograms()  
177 - , m_logOnDestroy(true)  
178 -{  
179 -}  
180 -  
181 -template <typename TContext, typename TValue, std::size_t Buckets>  
182 -HistogramProvider<TContext, TValue, Buckets>::~HistogramProvider()  
183 -{  
184 - if (m_logOnDestroy) {  
185 - for (const auto& h : m_histograms) {  
186 - std::cout << *h.second << std::endl;  
187 - }  
188 - }  
189 -}  
190 -  
191 -template <typename TContext, typename TValue, std::size_t Buckets>  
192 -void HistogramProvider<TContext, TValue, Buckets>::log(const HistogramType& hist, bool onlyChanged)  
193 -{  
194 - if ((onlyChanged && hist.isUpdated()) || !onlyChanged) {  
195 - MLOGIC_COMMON_INFO("HistogramProvider", "%1", hist);  
196 - }  
197 -}  
198 -  
199 -} // End namespace measurement  
200 -} // End namespace mqtt  
201 -} // End namespace components  
202 -} // End namespace osdev  
203 -  
204 -#endif // OSDEV_COMPONENTS_MQTT_MEASUREMENT_HISTOGRAMPROVIDER_H  
src/ihistogram.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MEASUREMENT_IHISTOGRAM_H  
23 -#define OSDEV_COMPONENTS_MQTT_MEASUREMENT_IHISTOGRAM_H  
24 -  
25 -// std  
26 -#include <ostream>  
27 -#include <string>  
28 -#include <vector>  
29 -  
30 -namespace osdev {  
31 -namespace components {  
32 -namespace mqtt {  
33 -namespace measurement {  
34 -  
35 -/**  
36 - * @brief Class that holds the dynamic part of a histogram.  
37 - * Used to take a snapshot of the histogram.  
38 - */  
39 -class HistogramData  
40 -{  
41 -public:  
42 - /**  
43 - * @brief Construct dynamic histrogram data.  
44 - * @param smallestValue A stringified version of the smallest recorded value since the last update.  
45 - * @param largestValue A stringified version of the largest recorded value since the last update.  
46 - * @param smallestValueSinceLastClear A stringified version of the smallest value as string since last clear.  
47 - * @param largestValueSinceLastClear A stringified version of the largest value as string since last clear.  
48 - * @param averageValueSinceLastClear A stringified version of the average value as string since last clear.  
49 - * @param nrOfValuesSinceLastClear Number of values since last clear.  
50 - * @param histCounts The histogram counts.  
51 - */  
52 - HistogramData(const std::string& smallestValue, const std::string& largestValue,  
53 - const std::string& smallestValueSinceLastClear,  
54 - const std::string& largestValueSinceLastClear,  
55 - const std::string& averageValueSinceLastClear,  
56 - std::size_t nrOfValuesSinceLastClear,  
57 - const std::vector<std::size_t>& histCounts)  
58 - : m_smallestValueString(smallestValue)  
59 - , m_largestValueString(largestValue)  
60 - , m_smallestValueSinceLastClearString(smallestValueSinceLastClear)  
61 - , m_largestValueSinceLastClearString(largestValueSinceLastClear)  
62 - , m_averageValueSinceLastClearString(averageValueSinceLastClear)  
63 - , m_numberOfValuesSinceLastClear(nrOfValuesSinceLastClear)  
64 - , m_data(histCounts)  
65 - {  
66 - }  
67 -  
68 - /**  
69 - * @return The smallest recorded value as a string.  
70 - */  
71 - const std::string& smallestValueString() const  
72 - {  
73 - return m_smallestValueString;  
74 - }  
75 -  
76 - /**  
77 - * @return The largest recorded value as a string.  
78 - */  
79 - const std::string& largestValueString() const  
80 - {  
81 - return m_largestValueString;  
82 - }  
83 -  
84 - /**  
85 - * @return The number of value since last clear.  
86 - */  
87 - std::size_t numberOfValuesSinceLastClear() const  
88 - {  
89 - return m_numberOfValuesSinceLastClear;  
90 - }  
91 -  
92 - /**  
93 - * @return The smallest value since last clear as a string.  
94 - */  
95 - const std::string& smallestValueSinceLastClearString() const  
96 - {  
97 - return m_smallestValueSinceLastClearString;  
98 - }  
99 -  
100 - /**  
101 - * @return The largest value since last clear as a string.  
102 - */  
103 - const std::string& largestValueSinceLastClearString() const  
104 - {  
105 - return m_largestValueSinceLastClearString;  
106 - }  
107 -  
108 - /**  
109 - * @return The average value since last clear as a string.  
110 - */  
111 - const std::string& averageValueSinceLastClearString() const  
112 - {  
113 - return m_averageValueSinceLastClearString;  
114 - }  
115 -  
116 - /**  
117 - * @return The histogram counts.  
118 - */  
119 - const std::vector<std::size_t>& data() const  
120 - {  
121 - return m_data;  
122 - }  
123 -  
124 -private:  
125 - std::string m_smallestValueString;  
126 - std::string m_largestValueString;  
127 - std::string m_smallestValueSinceLastClearString;  
128 - std::string m_largestValueSinceLastClearString;  
129 - std::string m_averageValueSinceLastClearString;  
130 - std::size_t m_numberOfValuesSinceLastClear;  
131 - std::vector<std::size_t> m_data;  
132 -};  
133 -  
134 -/**  
135 - * @brief Interface for histogram classes  
136 - * Can be used to store histograms in a container and visualize the histogram.  
137 - */  
138 -class IHistogram  
139 -{  
140 -public:  
141 - virtual ~IHistogram();  
142 -  
143 - /**  
144 - * @return The histogram identification (title).  
145 - */  
146 - virtual const std::string& id() const = 0;  
147 -  
148 - /**  
149 - * @return The number of buckets.  
150 - */  
151 - virtual std::size_t numBuckets() const = 0;  
152 -  
153 - /**  
154 - * @return The bucket width as a floating point value.  
155 - */  
156 - virtual double bucketWidth() const = 0;  
157 -  
158 - /**  
159 - * @return The minimum value of the histogram definition as a string.  
160 - */  
161 - virtual std::string minValueString() const = 0;  
162 -  
163 - /**  
164 - * @return The maximum value of the histogram definition as a string.  
165 - */  
166 - virtual std::string maxValueString() const = 0;  
167 -  
168 - /**  
169 - * @return The value unit as a a string.  
170 - */  
171 - virtual const std::string& unit() const = 0;  
172 -  
173 - /**  
174 - * @return The histogram data.  
175 - * This takes a snapshot of the histogram data.  
176 - */  
177 - virtual HistogramData histogramData() const = 0;  
178 -  
179 - /**  
180 - * @return The number of value since last clear.  
181 - */  
182 - virtual std::size_t numberOfValuesSinceLastClear() const = 0;  
183 -  
184 - /**  
185 - * @return The smallest value since last clear as a string.  
186 - */  
187 - virtual std::string smallestValueSinceLastClear() const = 0;  
188 -  
189 - /**  
190 - * @return The largest value since last clear as a string.  
191 - */  
192 - virtual std::string largestValueSinceLastClear() const = 0;  
193 -  
194 - /**  
195 - * @return The average value since last clear as a string.  
196 - */  
197 - virtual std::string averageValueSinceLastClear() const = 0;  
198 -  
199 - /**  
200 - * @brief Clears the values that are kept between successive clearRunningValues calls.  
201 - * These are:  
202 - * smallestValueSinceLastClear  
203 - * largestValueSinceLastClear  
204 - * averageValueSinceLastClear  
205 - */  
206 - virtual void clearRunningValues() = 0;  
207 -  
208 - /**  
209 - * @return The ascii representation of the histogram.  
210 - */  
211 - virtual std::string toString() const = 0;  
212 -};  
213 -  
214 -/**  
215 - * @brief Make an ascii visualisation of the given histogram data.  
216 - * @param histogram The histogram to visualize.  
217 - */  
218 -std::string visualizeHistogram(const IHistogram& histogram);  
219 -  
220 -/**  
221 - * @brief Stream operator for IHistogram instances.  
222 - */  
223 -std::ostream& operator<<(std::ostream& os, const IHistogram& rhs);  
224 -  
225 -} // End namespace measurement  
226 -} // End namespace mqtt  
227 -} // End namespace components  
228 -} // End namespace osdev  
229 -  
230 -#endif // OSDEV_COMPONENTS_MQTT_MEASUREMENT_IHISTOGRAM_H  
src/imqttclient.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_IMQTTCLIENT_H  
23 -#define OSDEV_COMPONENTS_MQTT_IMQTTCLIENT_H  
24 -  
25 -// std  
26 -#include <chrono>  
27 -#include <functional>  
28 -#include <set>  
29 -#include <string>  
30 -  
31 -// boost  
32 -#include <boost/optional.hpp>  
33 -  
34 -// mlogic::client  
35 -#include "istatecallback.h"  
36 -  
37 -// mlogic::mqtt  
38 -#include "connectionstatus.h"  
39 -#include "credentials.h"  
40 -#include "mqttmessage.h"  
41 -#include "token.h"  
42 -  
43 -namespace osdev {  
44 -namespace components {  
45 -namespace mqtt {  
46 -  
47 -/**  
48 - * @brief Interface that describes the minimal interface that a wrapper implementation needs to have in  
49 - * order to coorporate with the MqttClient class.  
50 - */  
51 -class IMqttClient : public virtual IStateCallback  
52 -{  
53 -public:  
54 - virtual ~IMqttClient() {}  
55 -  
56 - /**  
57 - * @brief Connect to the endpoint  
58 - * @param host The host name or ip address.  
59 - * @param port The port to use.  
60 - * @param credentials The credentials to use.  
61 - */  
62 - virtual void connect(const std::string& host, int port, const Credentials& credentials) = 0;  
63 -  
64 - /**  
65 - * @brief Connect to the endpoint  
66 - * @param endpoint an uri endpoint description.  
67 - */  
68 - virtual void connect(const std::string& endpoint) = 0;  
69 -  
70 - /**  
71 - * @brief Disconnect the client from the broker  
72 - */  
73 - virtual void disconnect() = 0;  
74 -  
75 - /**  
76 - * @brief Publish a message with a given quality of service (0, 1 or 2).  
77 - * @param message The message to publish.  
78 - * @param qos The quality of service to use.  
79 - * @return The token that identifies the publication (used in the deliveryCompleteCallback).  
80 - */  
81 - virtual Token publish(const MqttMessage& message, int qos) = 0;  
82 -  
83 - /**  
84 - * @brief Subscribe to a topic(filter).  
85 - * The combination of topic and qos makes a subscription unique on a wrapper client. When a topic has overlap  
86 - * with an existing subscription it is guaranteed that the given callback is only called once.  
87 - * @param topic The topic to subscribe to (can have wildcards). The topic can have overlap with existing topic subscriptions.  
88 - * @param qos The quality of service to use (0, 1 or 2).  
89 - * @param cb The callback that is called when messages are received for this subscription.  
90 - * @return A token that identifies the subscribe command.  
91 - */  
92 - virtual Token subscribe(const std::string& topic, int qos, const std::function<void(MqttMessage)>& cb) = 0;  
93 -  
94 - /**  
95 - * @brief Unsubscribe an existing subscription.  
96 - * The combination of topic and qos can occur on multiple wrapper clients. All subscriptions that match are unsubscribed.  
97 - * @param topic The topic to unsubscribe.  
98 - * @param qos The quality of service of the subscription (0, 1 or 2).  
99 - * @return A set of unsubscribe tokens identifying the unsubscribe commands. Usually the set will contain only one item.  
100 - */  
101 - virtual std::set<Token> unsubscribe(const std::string& topic, int qos) = 0;  
102 -  
103 - /**  
104 - * @brief Wait for all commands to complete.  
105 - * @param waitFor The number of milliseconds to wait for completetion of all commands.  
106 - * @return True when all commands have completed in time or false if not.  
107 - */  
108 - virtual bool waitForCompletion(std::chrono::milliseconds waitFor) const = 0;  
109 -  
110 - /**  
111 - * @brief Wait for a single command to complete.  
112 - * @param waitFor The number of milliseconds to wait for completetion of the command.  
113 - * @param token The token to wait for.  
114 - * @return True when the command has completed in time or false if not.  
115 - * @note Non existent tokens are also reported as completed.  
116 - */  
117 - virtual bool waitForCompletion(std::chrono::milliseconds waitFor, const Token& token) const = 0;  
118 -  
119 - /**  
120 - * @brief Wait for commands to complete.  
121 - * This method enables the user to wait for a set of commands. An empty set means to wait for all commands to complete.  
122 - * @param waitFor The number of milliseconds to wait for completetion of all commands.  
123 - * @param tokens The tokens to wait for. An empty set means to wait for all commands to complete.  
124 - * @return True when the commands have completed in time or false if not.  
125 - * @note Non existent tokens are also reported as completed.  
126 - */  
127 - virtual bool waitForCompletion(std::chrono::milliseconds waitFor, const std::set<Token>& tokens) const = 0;  
128 -  
129 - /**  
130 - * @brief Get the result of a command.  
131 - * @param token The token identifying the result.  
132 - * @return The command result when available.  
133 - */  
134 - virtual boost::optional<bool> commandResult(const Token& token) const = 0;  
135 -  
136 - /**  
137 - * @return The endpoint uri.  
138 - */  
139 - virtual std::string endpoint() const = 0;  
140 -};  
141 -  
142 -} // End namespace mqtt  
143 -} // End namespace components  
144 -} // End namespace osdev  
145 -  
146 -#endif // OSDEV_COMPONENTS_MQTT_IMQTTCLIENT_H  
src/imqttclientimpl.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_IMQTTCLIENTIMPL_H  
23 -#define OSDEV_COMPONENTS_MQTT_IMQTTCLIENTIMPL_H  
24 -  
25 -// std  
26 -#include <chrono>  
27 -#include <functional>  
28 -#include <ostream>  
29 -#include <set>  
30 -#include <string>  
31 -#include <vector>  
32 -  
33 -// boost  
34 -#include <boost/optional.hpp>  
35 -  
36 -// mlogic::mqtt  
37 -#include "connectionstatus.h"  
38 -#include "mqttmessage.h"  
39 -  
40 -namespace osdev {  
41 -namespace components {  
42 -namespace mqtt {  
43 -  
44 -/**  
45 - * @brief Interface that describes the minimal interface that a wrapper implementation needs to have in  
46 - * order to coorporate with the MqttClient class.  
47 - */  
48 -class IMqttClientImpl  
49 -{  
50 -public:  
51 - virtual ~IMqttClientImpl();  
52 -  
53 - /**  
54 - * @return id of this client.  
55 - */  
56 - virtual std::string clientId() const = 0;  
57 -  
58 - /**  
59 - * @return The connection status of the wrapper.  
60 - */  
61 - virtual ConnectionStatus connectionStatus() const = 0;  
62 -  
63 - /**  
64 - * @brief Connect the wrapper to the endpoint.  
65 - * @param wait A flag that indicates if the method should wait for a succesful connection.  
66 - * @return the operation token.  
67 - */  
68 - virtual std::int32_t connect(bool wait) = 0;  
69 -  
70 - /**  
71 - * @brief Disconnect the wrapper.  
72 - * @param wait A flag that indicates if the method should wait for a succesful disconnect. When true the method will wait for the timeoutMs value plus some additional time.  
73 - * @param timeoutMs A timeout in milliseconds. The timeout is used to give in flight messages a chance to get delivered. After the timeout the disconnect command is sent.  
74 - * @return the operation token.  
75 - */  
76 - virtual std::int32_t disconnect(bool wait, int timeoutMs) = 0;  
77 -  
78 - /**  
79 - * @brief Publish a message to an mqtt endpoint with a given quality of service.  
80 - * When the connection is in state reconnect the publish is saved so that it can be published later.  
81 - * @param message The message to send.  
82 - * @param qos The quality of service to use (0, 1 or 2).  
83 - * @return The message token. This token identifies the publication.  
84 - */  
85 - virtual std::int32_t publish(const MqttMessage& message, int qos) = 0;  
86 -  
87 - /**  
88 - * @brief Publish messages when client is reconnected.  
89 - */  
90 - virtual void publishPending() = 0;  
91 -  
92 - /**  
93 - * @brief Subscribe to a topic(filter).  
94 - * The combination of topic and qos makes a subscription unique. Subscriptions with the same topic filter  
95 - * but different qos are considered different, but they will overlap and cannot exist in the same wrapper.  
96 - * @param topic The topic to subscribe to (can have wildcards). The topic cannot have overlap with existing topic subscriptions.  
97 - * @param qos The quality of service to use (0, 1 or 2).  
98 - * @param cb The callback that is called when messages are received for this subscription.  
99 - * @return the operation token.  
100 - */  
101 - virtual std::int32_t subscribe(const std::string& topic, int qos, const std::function<void(MqttMessage msg)>& cb) = 0;  
102 -  
103 - /**  
104 - * @brief Resubscribe existing topicfilters.  
105 - * This method should be called only after a reconnect when subscriptions need to be reinstated.  
106 - */  
107 - virtual void resubscribe() = 0;  
108 -  
109 - /**  
110 - * @brief Unsubscribe an existing subscription.  
111 - * The combination of topic and qos make a subscription unique.  
112 - * @param topic The topic to unsubscribe.  
113 - * @param qos The quality of service of the subscription (0, 1 or 2).  
114 - * @return the operation token.  
115 - */  
116 - virtual std::int32_t unsubscribe(const std::string& topic, int qos) = 0;  
117 -  
118 - /**  
119 - * @brief Unsubscribe all subscriptions.  
120 - */  
121 - virtual void unsubscribeAll() = 0;  
122 -  
123 - /**  
124 - * @brief Wait for commands to complete.  
125 - * This method enables the user to wait for a set of tokens. An empty set means wait for all operations to complete.  
126 - * @param waitFor The number of milliseconds to wait for completetion of all commands.  
127 - * @param tokens The set of tokens to wait for.  
128 - * @return The number of milliseconds left.  
129 - */  
130 - virtual std::chrono::milliseconds waitForCompletion(std::chrono::milliseconds waitFor, const std::set<std::int32_t>& tokens) const = 0;  
131 -  
132 - /**  
133 - * @brief Check if a topic overlaps with existing topic subscriptions.  
134 - * @param topic The topic to test.  
135 - * @return true when overlap is detected, false otherwise.  
136 - */  
137 - virtual bool isOverlapping(const std::string& topic) const = 0;  
138 -  
139 - /**  
140 - * @brief Check if a topic overlaps with existing topic subscriptions.  
141 - * @param topic The topic to test.  
142 - * @param[out] existingTopic Contains the topic on which overlap is detected.  
143 - * @return true when overlap is detected. The existingTopic contains the topic on which overlap is detected, false otherwise.  
144 - */  
145 - virtual bool isOverlapping(const std::string& topic, std::string& existingTopic) const = 0;  
146 -  
147 - /**  
148 - * @return A vector with the pending operation tokens.  
149 - */  
150 - virtual std::vector<std::int32_t> pendingOperations() const = 0;  
151 -  
152 - /**  
153 - * @return true when client wrapper has pending subscriptions, false otherwise.  
154 - */  
155 - virtual bool hasPendingSubscriptions() const = 0;  
156 -  
157 - /**  
158 - * @return The operation result.  
159 - * @retval true operation has succeeded.  
160 - * @retval false operation has failed.  
161 - */  
162 - virtual boost::optional<bool> operationResult(std::int32_t token) const = 0;  
163 -};  
164 -  
165 -} // End namespace mqtt  
166 -} // End namespace components  
167 -} // End namespace osdev  
168 -  
169 -#endif // OSDEV_COMPONENTS_MQTT_IMQTTCLIENTIMPL_H  
src/istatecallback.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_ISTATECALLBACK_H  
23 -#define OSDEV_COMPONENTS_MQTT_ISTATECALLBACK_H  
24 -  
25 -// std  
26 -#include <ostream>  
27 -  
28 -// boost  
29 -#include <boost/signals2.hpp>  
30 -  
31 -namespace osdev {  
32 -namespace components {  
33 -namespace mqtt {  
34 -  
35 -/*!  
36 - * \brief Struct introduces a typed client identifier.  
37 - */  
38 -struct ClientIdentifier  
39 -{  
40 - /*!  
41 - * \brief Construct a ClientIdentifier  
42 - * \param id The client id. Default is empty.  
43 - */  
44 - explicit ClientIdentifier(const std::string& id = "")  
45 - : m_id(id)  
46 - {  
47 - }  
48 -  
49 - const std::string m_id; ///< Client identifier  
50 -};  
51 -  
52 -/*!  
53 - * \brief Enumeration of state codes.  
54 - * The states Unknown, CommunicationFailure, GeneralFailure, Good  
55 - * and Shutdown are used to communicate state about the server  
56 - * that is connected to. The states ConnectionFailure and Unregister  
57 - * communicate state about the client.  
58 - */  
59 -enum class StateEnum  
60 -{  
61 - Unknown, ///< State of underlying data source is unknown.  
62 - CommunicationFailure, ///< No communication with underlying data source.  
63 - GeneralFailure, ///< Some failure in the underlying data source.  
64 - Good, ///< Underlying data source is available.  
65 - Shutdown, ///< Underlying data source is shutting down.  
66 - ConnectionFailure, ///< Client connection has failed.  
67 - Unregister ///< Client is being unregistered.  
68 -};  
69 -  
70 -/*!  
71 - * \brief Stream a StateEnum value  
72 - */  
73 -std::ostream& operator<<(std::ostream& os, StateEnum rhs);  
74 -  
75 -/*!  
76 - * \brief Type for identifying state change callbacks.  
77 - */  
78 -using StateChangeCallbackHandle = std::uint32_t;  
79 -  
80 -class IStateCallback;  
81 -  
82 -/*!  
83 - * \brief Create an id for an IStateCallback object.  
84 - * \param idStatic - Static part of the id (name of the class).  
85 - * \param clientId - Client identifier. Can contain information on how  
86 - * the client is used for instance. If the id is empty  
87 - * it is not used.  
88 - * \param idDynamic - Dynamic part (object address).  
89 - * \return identifier as string  
90 - */  
91 -std::string createIdentifier(const std::string& idStatic, const ClientIdentifier& clientId, const IStateCallback* idDynamic);  
92 -  
93 -/*!  
94 - * \brief State callback interface.  
95 - * When a client implements this interface it can be registered on a  
96 - * server in order to handle state changes from the underlying data source.  
97 - * \note When the client is destroyed it is expected that it unregisters itself by calling  
98 - * clearAllStateChangeCallbacks().  
99 - */  
100 -class IStateCallback  
101 -{  
102 -public:  
103 - using SigStateChange = boost::signals2::signal<void(const IStateCallback*, StateEnum)>;  
104 - using SlotStateChange = SigStateChange::slot_type;  
105 -  
106 - virtual ~IStateCallback();  
107 -  
108 - /*!  
109 - * \brief Get a string that identifies this interface.  
110 - */  
111 - virtual std::string clientId() const = 0;  
112 -  
113 - /*!  
114 - * \brief Register a callback function that is called when the status changes.  
115 - * \param cb - The callback function to register.  
116 - * \return handle to the registered callback.  
117 - * \note Make sure that the callback function lives longer than the IStateCallback object.  
118 - * Otherwise unregister callback function before it is destroyed.  
119 - */  
120 - virtual StateChangeCallbackHandle registerStateChangeCallback(const SlotStateChange& cb) = 0;  
121 -  
122 - /*!  
123 - * \brief Unregister a previously registered callback function.  
124 - * If the callback function was not registered nothing happens.  
125 - * \param handle - Identifies the callback function to to unregister.  
126 - */  
127 - virtual void unregisterStateChangeCallback(StateChangeCallbackHandle handle) = 0;  
128 -  
129 - /*!  
130 - * \brief Remove all the registered callback functions.  
131 - */  
132 - virtual void clearAllStateChangeCallbacks() = 0;  
133 -  
134 - /*!  
135 - * \brief retuns the latest state received.  
136 - */  
137 - virtual StateEnum state() const = 0;  
138 -};  
139 -  
140 -} // End namespace mqtt  
141 -} // End namespace components  
142 -} // End namespace osdev  
143 -  
144 -#endif // OSDEV_COMPONENTS_MQTT_ISTATECALLBACK_H  
src/lockguard.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_LOCKGUARD_H  
23 -#define OSDEV_COMPONENTS_MQTT_LOCKGUARD_H  
24 -  
25 -// std  
26 -#include <mutex>  
27 -  
28 -// osdev::components::mqtt::measurement  
29 -#include "measure.h"  
30 -#include "utils.h"  
31 -  
32 -/**  
33 - * @brief Enable the lock measurements when macro MEASURE_LOCKS is defined.  
34 - * If the macro is not defined the NOP versions of the measure macros are used.  
35 - */  
36 -#ifdef MEASURE_LOCKS  
37 -#define OSDEV_COMPONENTS_MEASURELOCK OSDEV_COMPONENTS_MEASUREMENT_MEASURE  
38 -#define OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC  
39 -#else  
40 -#define OSDEV_COMPONENTS_MEASURELOCK OSDEV_COMPONENTS_MEASUREMENT_MEASURE_NOP  
41 -#define OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC_NOP  
42 -#endif  
43 -  
44 -/**  
45 - * @brief Create a lockguard for a given mutex in a specific context.  
46 - * @param mutexVariableName The name of the mutex.  
47 - * @param mutexObtainer The mutex to lock. This can also be a function that returns a mutex.  
48 - * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances.  
49 - */  
50 -#define OSDEV_COMPONENTS_LOCKGUARD_OBTAINER(mutexVariableName, mutexObtainer) \  
51 - OSDEV_COMPONENTS_MEASURELOCK(LOCKGUARD, std::lock_guard<std::mutex> Lock__Guard__##mutexVariableName##__(mutexObtainer), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \  
52 - osdev::components::mqtt::apply_unused_parameters(Lock__Guard__##mutexVariableName##__);  
53 -  
54 -/**  
55 - * @brief Create a lockguard for a given mutex in a specific context.  
56 - * @param mutexVariableName The name of the mutex.  
57 - * @param mutexObtainer The mutex to lock. This can also be a function that returns a mutex.  
58 - * @param id The id that identifies this specific lock guard. Used for measuring timings.  
59 - * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock.  
60 - */  
61 -#define OSDEV_COMPONENTS_LOCKGUARD_SPECIFIC_OBTAINER(mutexVariableName, mutexObtainer, id) \  
62 - OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC(id, LOCKGUARD, std::lock_guard<std::mutex> Lock__Guard__##mutexVariableName##__(mutexObtainer), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \  
63 - osdev::components::mqtt::apply_unused_parameters(Lock__Guard__##mutexVariableName##__);  
64 -  
65 -/**  
66 - * @brief Create a lockguard for a given recursive mutex in a specific context.  
67 - * @param mutexVariableName The name of the mutex.  
68 - * @param mutexObtainer The mutex to lock. This can also be a function that returns a mutex.  
69 - * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances.  
70 - */  
71 -#define OSDEV_COMPONENTS_RECURSIVELOCKGUARD_OBTAINER(mutexVariableName, mutexObtainer) \  
72 - OSDEV_COMPONENTS_MEASURELOCK(RECURSIVELOCKGUARD, std::lock_guard<std::recursive_mutex> Lock__Guard__##mutexVariableName##__(mutexObtainer), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \  
73 - osdev::components::mqtt::apply_unused_parameters(Lock__Guard__##mutexVariableName##__);  
74 -  
75 -/**  
76 - * @brief Create a lockguard for a given recursive mutex in a specific context.  
77 - * @param mutexVariableName The name of the mutex.  
78 - * @param mutexObtainer The mutex to lock. This can also be a function that returns a mutex.  
79 - * @param id The id that identifies this specific lock guard. Used for measuring timings.  
80 - * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock.  
81 - */  
82 -#define OSDEV_COMPONENTS_RECURSIVELOCKGUARD_SPECIFIC_OBTAINER(mutexVariableName, mutexObtainer, id) \  
83 - OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC(id, RECURSIVELOCKGUARD, std::lock_guard<std::recursive_mutex> Lock__Guard__##mutexVariableName##__(mutexVariableName), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \  
84 - osdev::components::mqtt::apply_unused_parameters(Lock__Guard__##mutexVariableName##__);  
85 -  
86 -/**  
87 - * @brief Create a lockguard for a given bare mutex in a specific context.  
88 - * @param mutexVariableName The name of the mutex.  
89 - * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances.  
90 - */  
91 -#define OSDEV_COMPONENTS_LOCKGUARD(mutexVariableName) \  
92 - OSDEV_COMPONENTS_LOCKGUARD_OBTAINER(mutexVariableName, mutexVariableName)  
93 -  
94 -/**  
95 - * @brief Create a lockguard for a given bare mutex in a specific context.  
96 - * @param mutexVariableName The name of the mutex.  
97 - * @param id The id that identifies this specific lock guard. Used for measuring timings.  
98 - * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock.  
99 - */  
100 -#define OSDEV_COMPONENTS_LOCKGUARD_SPECIFIC(mutexVariableName, id) \  
101 - OSDEV_COMPONENTS_LOCKGUARD_SPECIFIC_OBTAINER(mutexVariableName, mutexVariableName, id)  
102 -  
103 -/**  
104 - * @brief Create a lockguard for a given bare recursive mutex in a specific context.  
105 - * @param mutexVariableName The name of the mutex.  
106 - * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances.  
107 - */  
108 -#define OSDEV_COMPONENTS_RECURSIVELOCKGUARD(mutexVariableName) \  
109 - OSDEV_COMPONENTS_RECURSIVELOCKGUARD_OBTAINER(mutexVariableName, mutexVariableName)  
110 -  
111 -/**  
112 - * @brief Create a lockguard for a given bare recursive mutex in a specific context.  
113 - * @param mutexVariableName The name of the mutex.  
114 - * @param id The id that identifies this specific lock guard. Used for measuring timings.  
115 - * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances.  
116 - */  
117 -#define OSDEV_COMPONENTS_RECURSIVELOCKGUARD_SPECIFIC(mutexVariableName, id) \  
118 - OSDEV_COMPONENTS_RECURSIVELOCKGUARD_SPECIFIC_OBTAINER(mutexVariableName, mutexVariableName, id)  
119 -  
120 -/**  
121 - * @brief Defines the lock name that is used by the OSDEV_COMPONENTS_UNIQUELOCK_* macros  
122 - */  
123 -#define OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName) Unique__Lock__##mutexVariableName##__  
124 -  
125 -/**  
126 - * @brief Create a uniqeue lock for a given mutex.  
127 - * @param mutexVariableName The name of the mutex.  
128 - * @param mutexObtainer The mutex to lock. This can also be a function that returns a mutex.  
129 - * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances.  
130 - */  
131 -#define OSDEV_COMPONENTS_UNIQUELOCK_CREATE_OBTAINER(mutexVariableName, mutexObtainer) \  
132 - OSDEV_COMPONENTS_MEASURELOCK(UNIQUELOCK_CREATE, std::unique_lock<std::mutex> OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName)(mutexObtainer), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \  
133 - osdev::components::mqtt::apply_unused_parameters(OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName));  
134 -  
135 -/**  
136 - * @brief Create a uniqeue lock for a given mutex.  
137 - * @param mutexVariableName The name of the mutex.  
138 - * @param mutexObtainer The mutex to lock. This can also be a function that returns mutex.  
139 - * @param id The id that identifies this specific lock guard. Used for measuring timings.  
140 - * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock.  
141 - */  
142 -#define OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC_OBTAINER(mutexVariableName, mutexObtainer, id) \  
143 - OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC(id, UNIQUELOCK_CREATE, std::unique_lock<std::mutex> OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName)(mutexObtainer), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \  
144 - osdev::components::mqtt::apply_unused_parameters(OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName));  
145 -  
146 -/**  
147 - * @brief Create a uniqeue lock for a given bare mutex.  
148 - * @param mutexVariableName The name of the mutex.  
149 - * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances.  
150 - */  
151 -#define OSDEV_COMPONENTS_UNIQUELOCK_CREATE(mutexVariableName) \  
152 - OSDEV_COMPONENTS_UNIQUELOCK_CREATE_OBTAINER(mutexVariableName, mutexVariableName)  
153 -  
154 -/**  
155 - * @brief Create a uniqeue lock for a given bare mutex.  
156 - * @param mutexVariableName The name of the mutex.  
157 - * @param id The id that identifies this specific unique lock. Used for measuring timings.  
158 - * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock.  
159 - */  
160 -#define OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC(mutexVariableName, id) \  
161 - OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC_OBTAINER(mutexVariableName, mutexVariableName, id)  
162 -  
163 -/**  
164 - * @brief Lock a given uniqeue lock.  
165 - * @param mutexVariableName The name of the mutex from which the lockname is derived.  
166 - * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances.  
167 - */  
168 -#define OSDEV_COMPONENTS_UNIQUELOCK_LOCK(mutexVariableName) \  
169 - OSDEV_COMPONENTS_MEASURELOCK(UNIQUELOCK_LOCK, OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName).lock(), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100)  
170 -  
171 -/**  
172 - * @brief Lock a given uniqeue lock.  
173 - * @param mutexVariableName The name of the mutex from which the lockname is derived.  
174 - * @param id The id that identifies this specific unique lock guard. Used for measuring timings.  
175 - * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock.  
176 - */  
177 -#define OSDEV_COMPONENTS_UNIQUELOCK_LOCK_SPECIFIC(mutexVariableName, id) \  
178 - OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC(id, UNIQUELOCK_LOCK, OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName).lock(), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100)  
179 -  
180 -/**  
181 - * @brief Unlock a given uniqeue lock.  
182 - * @param mutexVariableName The name of the mutex from which the lockname is derived.  
183 - */  
184 -#define OSDEV_COMPONENTS_UNIQUELOCK_UNLOCK(mutexVariableName) \  
185 - OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName).unlock();  
186 -  
187 -/**  
188 - * @brief Unlock a given uniqeue lock.  
189 - * @param mutexVariableName The name of the mutex from which the lockname is derived.  
190 - * @param id The id that identifies this specific unique lock guard. Can be used for measuring timings.  
191 - */  
192 -#define OSDEV_COMPONENTS_UNIQUELOCK_UNLOCK_SPECIFIC(mutexVariableName, id) \  
193 - OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName).unlock();  
194 -  
195 -namespace osdev {  
196 -namespace components {  
197 -namespace mqtt {  
198 -  
199 -/**  
200 - * @brief Context tag type.  
201 - */  
202 -struct measure_locking_tag  
203 -{  
204 -};  
205 -  
206 -/**  
207 - * @brief Type for measuring lock timings  
208 - * The unit is microseconds and the values are expected between 0 and 100 microseconds.  
209 - * This type is used to construct a timing histogram.  
210 - */  
211 -struct MeasureLockingValue  
212 -{  
213 - /**  
214 - * @brief The value type of the timing value.  
215 - */  
216 - using value_type = std::chrono::microseconds;  
217 -  
218 - const value_type minValue = value_type(0); ///< Constant mininum value.  
219 - const value_type maxValue = value_type(100); ///< Constant maximum value.  
220 -  
221 - const char* unit = "us"; ///< The value unit.  
222 -};  
223 -  
224 -} // End namespace mqtt  
225 -} // End namespace components  
226 -} // End namespace osdev  
227 -  
228 -#endif // OSDEV_COMPONENTS_MQTT_LOCKGUARD_H  
src/macrodefs.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MACRODEFS_H  
23 -#define OSDEV_COMPONENTS_MQTT_MACRODEFS_H  
24 -  
25 -#include <type_traits>  
26 -  
27 -#include "compiletimestring.h"  
28 -  
29 -/// @brief Helper macro to stringify a symbol  
30 -#define OSDEV_COMPONENTS_STRINGIFY(x) #x  
31 -  
32 -/// @brief Use this macro to safely stringify a symbol  
33 -/// This will also work for nested macro's  
34 -#define OSDEV_COMPONENTS_TOSTRING(x) OSDEV_COMPONENTS_STRINGIFY(x)  
35 -  
36 -/// @brief Helper macro to combine two symbols  
37 -#define OSDEV_COMPONENTS_COMBINER(x, y) x##y  
38 -  
39 -/// @brief Use this macro to safely combine two symbols  
40 -/// This will also work for nested macro's  
41 -#define OSDEV_COMPONENTS_COMBINE(x, y) OSDEV_COMPONENTS_COMBINER(x, y)  
42 -  
43 -/// @brief Macro that reduces a path to the basename  
44 -#define OSDEV_COMPONENTS_MANAGEDBASEFILENAME \  
45 - OSDEV_COMPONENTS_CSTRING_BOUNDED(__FILE__, osdev::components::rfind(__FILE__, '/') + 1, sizeof(__FILE__) - 1)  
46 -  
47 -/// @brief Compiletime test if an instance derives from a certain base class  
48 -#define OSDEV_COMPONENTS_DERIVESFROM(derived, baseType) \  
49 - static_assert(std::is_base_of<baseType, \  
50 - typename std::remove_pointer<typename std::remove_reference<decltype(derived)>::type>::type>::value, \  
51 - OSDEV_COMPONENTS_TOSTRING(derived) " must be derived from " OSDEV_COMPONENTS_TOSTRING(baseType))  
52 -  
53 -#endif //OSDEV_COMPONENTS_MQTT_MACRODEFS_H  
src/measure.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MEASUREMENT_MEASURE_H  
23 -#define OSDEV_COMPONENTS_MQTT_MEASUREMENT_MEASURE_H  
24 -  
25 -#include "macrodefs.h"  
26 -#include "histogramprovider.h"  
27 -#include "timemeasurement.h"  
28 -  
29 -namespace osdev {  
30 -namespace components {  
31 -namespace mqtt {  
32 -namespace measurement {  
33 -  
34 -inline std::string createId(const std::string& operationName, const std::string& dynamicId)  
35 -{  
36 - return operationName + (dynamicId.empty() ? std::string{} : std::string(" ") + dynamicId);  
37 -}  
38 -  
39 -} // End namespace measurement  
40 -} // End namespace mqtt  
41 -} // End namespace components  
42 -} // End namespace osdev  
43 -  
44 -#define OSDEV_COMPONENTS_MEASUREMENT_LOCATION \  
45 - (OSDEV_COMPONENTS_MANAGEDBASEFILENAME + OSDEV_COMPONENTS_CSTRING(":" OSDEV_COMPONENTS_TOSTRING(__LINE__))).chars  
46 -  
47 -/**  
48 - * @brief Macro helper that sets up a TimeMeasurement on an operation.  
49 - * The operation must have observable side effects otherwise the compiler might move the operation from in between the time measurements.  
50 - * @param operationName The name of the operation. This is part of the id under which the measurements are registered.  
51 - * @param dynamicId The dynamic identification of this measurement. This id makes different instances of the same operation unique.  
52 - * The dynamicId must be an expression that yields a string like object. The dynamic id is part of the id under which the  
53 - * measurements are registered.  
54 - * @param operation The operation to perform.  
55 - * @param context The context tag used to identify the HistogramProvider.  
56 - * @param valueType A datatype that can be used by HistogramProvider.  
57 - * @param numBuckets The number of buckets to use for the histogram.  
58 - * @param boolOnDestroy Boolean value that makes the measurement measure on destruction.  
59 - */  
60 -#define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_HELPER(operationName, dynamicId, operation, context, valueType, numBuckets, boolOnDestroy) \  
61 - static const std::string OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(ID__, __LINE__), __) = \  
62 - std::string(OSDEV_COMPONENTS_CSTRING(#operationName).chars); \  
63 - osdev::components::mqtt::measurement::TimeMeasurement OSDEV_COMPONENTS_COMBINE( \  
64 - OSDEV_COMPONENTS_COMBINE(TM__, __LINE__), __)( \  
65 - osdev::components::mqtt::measurement::createId(OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(ID__, __LINE__), __), dynamicId), \  
66 - [](const std::string& id, std::chrono::steady_clock::time_point, std::chrono::microseconds, std::chrono::microseconds sinceLast) { \  
67 - osdev::components::mqtt::measurement::HistogramProvider<context, valueType, numBuckets>::instance().addValue(id, sinceLast); \  
68 - }, \  
69 - boolOnDestroy); \  
70 - operation;  
71 -  
72 -/**  
73 - * @brief Make a measurement before and after an operation.  
74 - * The operation must have observable side effects otherwise the compiler might move the operation from in between the time measurements.  
75 - * @param operationName The name under which the measurements are registered.  
76 - * @param operation The operation to perform.  
77 - * @param context The context tag used to identify the HistogramProvider.  
78 - * @param valueType A datatype that can be used by HistogramProvider.  
79 - * @param numBuckets The number of buckets to use for the histogram.  
80 - */  
81 -#define OSDEV_COMPONENTS_MEASUREMENT_MEASURE(operationName, operation, context, valueType, numBuckets) \  
82 - OSDEV_COMPONENTS_MEASUREMENT_MEASURE_HELPER(operationName, OSDEV_COMPONENTS_MEASUREMENT_LOCATION, operation, context, valueType, numBuckets, false) \  
83 - OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(TM__, __LINE__), __).measure();  
84 -  
85 -/**  
86 - * @brief Make a measurement on a return operation.  
87 - * The operation must have observable side effects otherwise the compiler might move the operation from in between the time measurements.  
88 - * @param operationName The name under which the measurements are registered.  
89 - * @param operation The operation to perform.  
90 - * @param context The context tag used to identify the HistogramProvider.  
91 - * @param valueType A datatype that can be used by HistogramProvider.  
92 - * @param numBuckets The number of buckets to use for the histogram.  
93 - */  
94 -#define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_ONDESTROY(operationName, operation, context, valueType, numBuckets) \  
95 - OSDEV_COMPONENTS_MEASUREMENT_MEASURE_HELPER(operationName, OSDEV_COMPONENTS_MEASUREMENT_LOCATION, operation, context, valueType, numBuckets, true)  
96 -  
97 -/**  
98 - * @brief Make a measurement on a return operation.  
99 - * The operation must have observable side effects otherwise the compiler might move the operation from in between the time measurements.  
100 - * @param operationName The name under which the measurements are registered.  
101 - * @param dynamicId An extra identification to discern between instances of the same operation. The dynamicId must be an expression that  
102 - * yields a string like object.  
103 - * @param operation The operation to perform.  
104 - * @param context The context tag used to identify the HistogramProvider.  
105 - * @param valueType A datatype that can be used by HistogramProvider.  
106 - * @param numBuckets The number of buckets to use for the histogram.  
107 - */  
108 -#define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC_ONDESTROY(operationName, dynamicId, operation, context, valueType, numBuckets) \  
109 - OSDEV_COMPONENTS_MEASUREMENT_MEASURE_HELPER(operationName, dynamicId, operation, context, valueType, numBuckets, true)  
110 -  
111 -/**  
112 - * @brief Nop version that only performs the operation.  
113 - */  
114 -#define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_ONDESTROY_NOP(operationName, operation, context, valueType, numBuckets) operation;  
115 -  
116 -/**  
117 - * @brief Nop version that only performs the operation.  
118 - */  
119 -#define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_NOP(operationName, operation, context, valueType, numBuckets) operation;  
120 -  
121 -/**  
122 - * @brief Nop version that only performs the operation.  
123 - */  
124 -#define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC_ONDESTROY_NOP(operationName, dynamicId, operation, context, valueType, numBuckets) operation;  
125 -  
126 -/**  
127 - * @brief Make a measurement before and after an operation for a specific instance of the operation.  
128 - * The operation must have observable side effects otherwise the compiler might move the operation from in between the time measurements.  
129 - * @param dynamicId An extra identification to discern between instances of the same operation.  
130 - * @param operationName The name under which the measurements are registered.  
131 - * @param operation The operation to perform.  
132 - * @param context The context tag used to identify the HistogramProvider.  
133 - * @param valueType A datatype that can be used by HistogramProvider.  
134 - * @param numBuckets The number of buckets to use for the histogram.  
135 - */  
136 -#define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC(dynamicId, operationName, operation, context, valueType, numBuckets) \  
137 - auto OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(IDPREFIX__, __LINE__), __) = \  
138 - OSDEV_COMPONENTS_MANAGEDBASEFILENAME + OSDEV_COMPONENTS_CSTRING(":" OSDEV_COMPONENTS_TOSTRING(__LINE__) ", function "); \  
139 - auto OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(IDPOSTFIX__, __LINE__), __) = OSDEV_COMPONENTS_CSTRING(", " #operationName " "); \  
140 - static const std::string OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(ID__, __LINE__), __) = \  
141 - std::string(OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(IDPREFIX__, __LINE__), __).chars) + \  
142 - std::string(__func__) + \  
143 - OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(IDPOSTFIX__, __LINE__), __).chars; \  
144 - osdev::components::mqtt::measurement::TimeMeasurement OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(TM__, __LINE__), __)( \  
145 - OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(ID__, __LINE__), __) + dynamicId, \  
146 - [](const std::string& id, std::chrono::steady_clock::time_point, std::chrono::microseconds, std::chrono::microseconds sinceLast) { \  
147 - osdev::components::mqtt::measurement::HistogramProvider<context, valueType, numBuckets>::instance().addValue(id, sinceLast); \  
148 - }, \  
149 - false); \  
150 - operation; \  
151 - OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(TM__, __LINE__), __).measure();  
152 -  
153 -/**  
154 - * @brief Nop version that only performs the operation.  
155 - */  
156 -#define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC_NOP(dynamicId, operationName, operation, context, valueType, numBuckets) operation;  
157 -  
158 -#endif // OSDEV_COMPONENTS_MEASUREMENT_MEASUREMENT_H  
src/metaprogrammingdefs.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_METAPROGRAMMINGDEFS_H  
23 -#define OSDEV_COMPONENTS_MQTT_METAPROGRAMMINGDEFS_H  
24 -  
25 -#include <cstddef> // for std::size_t  
26 -#include <sstream>  
27 -#include <string>  
28 -  
29 -#include "utils.h"  
30 -  
31 -/**  
32 - * @brief Create a type trait that checks for the existence of a member in a struct.  
33 - * @param memberName The member name  
34 - *  
35 - * A call such as OSDEV_COMPONENTS_HASMEMBER_TRAIT(onSuccess) leads to a type trait has_onSuccess.  
36 - */  
37 -#define OSDEV_COMPONENTS_HASMEMBER_TRAIT(memberName) \  
38 - template <typename T, typename = void> \  
39 - struct has_##memberName : public std::false_type \  
40 - { \  
41 - }; \  
42 - \  
43 - template <typename T> \  
44 - struct has_##memberName<T, osdev::components::mqtt::void_t<decltype(std::declval<T>().memberName)>> : public std::true_type \  
45 - { \  
46 - };  
47 -  
48 -/**  
49 - * @brief Create a type trait that checks for the existence of a member method with no parameters.  
50 - * @param methodName The method name  
51 - * @param postfix An extra postfix that is added to the type trait struct.  
52 - * This makes it possible create type traits that check for  
53 - * overloaded methods.  
54 - *  
55 - * A call such as OSDEV_COMPONENTS_HASMETHOD_TRAIT(capacity,1) leads to a type trait has_capacity1.  
56 - */  
57 -#define OSDEV_COMPONENTS_HASMETHOD_TRAIT(methodName, postfix) \  
58 - template <typename T, typename = void> \  
59 - struct has_##methodName##postfix : public std::false_type \  
60 - { \  
61 - }; \  
62 - \  
63 - template <typename T> \  
64 - struct has_##methodName##postfix<T, osdev::components::mqtt::void_t<decltype(std::declval<T>().methodName())>> : public std::true_type \  
65 - { \  
66 - };  
67 -  
68 -/**  
69 - * @brief Create a type trait that checks for the existence of a member method with 1 or more parameters.  
70 - * @param methodName The method name  
71 - * @param postfix An extra postfix that is added to the type trait struct.  
72 - * This makes it possible create type traits that check for  
73 - * overloaded methods.  
74 - * @param ... Variable number of arguments. These can be values, but also declval constructs such as std::declval<MyClass>().  
75 - *  
76 - * A call such as OSDEV_COMPONENTS_HASMETHODWP_TRAIT(capacity,,"string") leads to a type trait has_capacity that  
77 - * checks for the existence of a method capacity that accepts a const char pointer.  
78 - */  
79 -#define OSDEV_COMPONENTS_HASMETHODWP_TRAIT(methodName, postfix, ...) \  
80 - template <typename T, typename = void> \  
81 - struct has_##methodName##postfix : public std::false_type \  
82 - { \  
83 - }; \  
84 - \  
85 - template <typename T> \  
86 - struct has_##methodName##postfix<T, osdev::components::mqtt::void_t<decltype(std::declval<T>().methodName(__VA_ARGS__))>> : public std::true_type \  
87 - { \  
88 - };  
89 -  
90 -namespace osdev {  
91 -namespace components {  
92 -namespace mqtt {  
93 -  
94 -/**  
95 - * @brief Used to detect ill formed types in a SFINAE context.  
96 - * If the parameter pack Ts contains an invalid type, struct make_void cannot be expanded.  
97 - */  
98 -template <typename... Ts>  
99 -struct make_void  
100 -{  
101 - using type = void;  
102 -};  
103 -  
104 -/**  
105 - * @brief Introduced in c++17 (but will also work in c++11)  
106 - */  
107 -template <typename... Ts>  
108 -using void_t = typename make_void<Ts...>::type;  
109 -  
110 -/// @brief Build an index list that can be used to traverse another list (f.i. a char array).  
111 -/// Recursive definition.  
112 -/// Start with an empty indices list. Build the indices list recursively.  
113 -/// upper-1, indices... becomes the indices... in the next recursive call.  
114 -template <std::size_t lower, std::size_t upper,  
115 - template <std::size_t...> class meta_functor, std::size_t... Is>  
116 -struct apply_bounded_range  
117 -{  
118 - typedef typename apply_bounded_range<lower, upper - 1, meta_functor, upper - 1, Is...>::result result;  
119 -};  
120 -  
121 -/// @brief Terminator of apply_bounded_range.  
122 -/// Terminates when the upper bound (which runs) is equal to the lower bound.  
123 -template <std::size_t lower, template <std::size_t...> class meta_functor, std::size_t... Is>  
124 -struct apply_bounded_range<lower, lower, meta_functor, Is...>  
125 -{  
126 - typedef typename meta_functor<Is...>::result result;  
127 -};  
128 -  
129 -/**  
130 - * @brief Helper method to perform static_assert on the expected count of a parameter pack.  
131 - */  
132 -template <std::size_t expectedCount, typename... Args>  
133 -void static_assert_count()  
134 -{  
135 - constexpr std::size_t actualCount = sizeof...(Args);  
136 - static_assert(expectedCount == actualCount, "Unexpected parameter count.");  
137 -}  
138 -  
139 -/**  
140 - * @brief Helper method to convert a type to std::string.  
141 - * @param d_first The output iterator to write the converted string to.  
142 - * @param arg The argument to convert to std::string.  
143 - */  
144 -template <typename OutputIt, typename T>  
145 -int apply_to_string_one(OutputIt d_first, const T& arg)  
146 -{  
147 - std::ostringstream ss;  
148 - ss << arg;  
149 - *d_first++ = ss.str();  
150 - return 0;  
151 -}  
152 -  
153 -/**  
154 - * @brief Converts all parameters to std::string.  
155 - * @param d_first The output iterator to write the converted strings to.  
156 - * @param args The arguments to convert to std::string.  
157 - */  
158 -template <typename OutputIt, typename... Args>  
159 -void apply_to_string(OutputIt d_first, Args&&... args)  
160 -{  
161 - // d_first is not used when args parameter pack is empty.  
162 - apply_unused_parameters(d_first);  
163 -  
164 - // We need to use the expand_type trick in order to be able to use an initializer list  
165 - // so that we can call the method for every variadic argument  
166 - using expand_type = int[];  
167 - // Array must be initialized with values. Add a single value so that the array can be initialized when the parameter pack is empty.  
168 - expand_type et{ 0, apply_to_string_one(d_first, std::forward<Args>(args))... };  
169 - apply_unused_parameters(et);  
170 -}  
171 -  
172 -/**  
173 - * @brief Helper that removes const, volatile and reference from a type.  
174 - * @note Defined in std C++20.  
175 - */  
176 -template <typename T>  
177 -struct remove_cvref  
178 -{  
179 - using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;  
180 -};  
181 -  
182 -} // End namespace mqtt  
183 -} // End namespace components  
184 -} // End namespace osdev  
185 -  
186 -#endif // OSDEV_COMPONENTS_MQTT_METAPROGRAMMINGDEFS_H  
src/mqttclient.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MQTTCLIENT_H  
23 -#define OSDEV_COMPONENTS_MQTT_MQTTCLIENT_H  
24 -  
25 -// std  
26 -#include <condition_variable>  
27 -#include <memory>  
28 -#include <mutex>  
29 -#include <set>  
30 -#include <thread>  
31 -#include <vector>  
32 -  
33 -// osdev::components::mqtt  
34 -#include "synchronizedqueue.h"  
35 -#include "istatecallback.h"  
36 -#include "serverstate.h"  
37 -  
38 -#include "imqttclient.h"  
39 -  
40 -namespace osdev {  
41 -namespace components {  
42 -namespace mqtt {  
43 -  
44 -// Forward definition  
45 -class IMqttClientImpl;  
46 -  
47 -class MqttClient : public virtual IMqttClient  
48 -{  
49 -public:  
50 - /*!  
51 - * \brief Construct an instance of the MqttClient.  
52 - * \param clientId The client identification used in the connection to the mqtt broker.  
53 - * \param deliveryCompleteCallback Optional callback used to signal completion of a publication.  
54 - */  
55 - MqttClient( const std::string& clientId, const std::function<void(const Token& token)>& deliveryCompleteCallback = std::function<void(const Token& token)>{});  
56 - virtual ~MqttClient() override;  
57 -  
58 - // Non copyable, non movable  
59 - MqttClient(const MqttClient&) = delete;  
60 - MqttClient& operator=(const MqttClient&) = delete;  
61 - MqttClient(MqttClient&&) = delete;  
62 - MqttClient& operator=(MqttClient&&) = delete;  
63 -  
64 - /**  
65 - * @see IStateCallback  
66 - */  
67 - virtual std::string clientId() const override;  
68 -  
69 - /**  
70 - * @see IStateCallback  
71 - */  
72 - virtual StateChangeCallbackHandle registerStateChangeCallback(const SlotStateChange& cb) override;  
73 -  
74 - /**  
75 - * @see IStateCallback  
76 - */  
77 - virtual void unregisterStateChangeCallback(StateChangeCallbackHandle handle) override;  
78 -  
79 - /**  
80 - * @see IStateCallback  
81 - */  
82 - virtual void clearAllStateChangeCallbacks() override;  
83 -  
84 - /**  
85 - * @see IStateCallback  
86 - */  
87 - virtual StateEnum state() const override;  
88 -  
89 - // MqttClient interface  
90 -  
91 - /**  
92 - * @see IMqttClient  
93 - */  
94 - virtual void connect(const std::string& host, int port, const Credentials& credentials) override;  
95 -  
96 - /**  
97 - * @see IMqttClient  
98 - */  
99 - virtual void connect(const std::string& endpoint) override;  
100 -  
101 - /**  
102 - * @see IMqttClient  
103 - */  
104 - virtual void disconnect() override;  
105 -  
106 - /**  
107 - * @see IMqttClient  
108 - */  
109 - virtual Token publish(const MqttMessage& message, int qos) override;  
110 -  
111 - /**  
112 - * @see IMqttClient  
113 - * When an overlapping subscription is detected a new connection has to be created. This is a synchronous action  
114 - * and this method will wait for the connection to be up.  
115 - */  
116 - virtual Token subscribe(const std::string& topic, int qos, const std::function<void(MqttMessage)>& cb) override;  
117 -  
118 - /**  
119 - * @see IMqttClient  
120 - */  
121 - virtual std::set<Token> unsubscribe(const std::string& topic, int qos) override;  
122 -  
123 - /**  
124 - * @see IMqttClient  
125 - */  
126 - virtual bool waitForCompletion(std::chrono::milliseconds waitFor) const override;  
127 -  
128 - /**  
129 - * @see IMqttClient  
130 - */  
131 - virtual bool waitForCompletion(std::chrono::milliseconds waitFor, const Token& token) const override;  
132 -  
133 - /**  
134 - * @see IMqttClient  
135 - */  
136 - virtual bool waitForCompletion(std::chrono::milliseconds waitFor, const std::set<Token>& tokens) const override;  
137 -  
138 - /**  
139 - * @see IMqttClient  
140 - */  
141 - virtual boost::optional<bool> commandResult(const Token& token) const override;  
142 -  
143 - /**  
144 - * @see IMqttClient  
145 - */  
146 - virtual std::string endpoint() const override;  
147 -  
148 -private:  
149 - /*!  
150 - * \brief Callback used to pick up the connection status of the wrappers.  
151 - * \param id The client id.  
152 - * \param cs The connection status.  
153 - */  
154 - void connectionStatusChanged( const std::string& id, ConnectionStatus cs );  
155 -  
156 - /*!  
157 - * \brief Callback for handling delivery complete.  
158 - * \param clientId The identifier of the client on which the publish command is executed.  
159 - * \param token The token identifies the publish command.  
160 - */  
161 - void deliveryComplete( const std::string& clientId, std::int32_t token );  
162 -  
163 - /**  
164 - * \brief Wait for commands to complete including active tokens in this client.  
165 - * The interface mutex is not locked by this method.  
166 - * First wait for client commands to complete (use method waitForCompletionInternalClients)  
167 - * and then wait for publish delivery callbacks to complete.  
168 - * \param clients - Vector with client wrapper pointers that need to be waited on.  
169 - * \param[in,out] waitFor - The number of milliseconds to wait for completetion of all commands and delivery callbacks.  
170 - * \param tokens - The tokens to wait for. An empty set means to wait for all commands on all clients to complete  
171 - * including all publish delivery callbacks.  
172 - * \return True when commands have completed in time including delivery callbacks or false if not.  
173 - */  
174 - bool waitForCompletionInternal(const std::vector<IMqttClientImpl*>& clients, std::chrono::milliseconds waitFor, const std::set<Token>& tokens) const;  
175 -  
176 - /**  
177 - * \brief Wait for commands on the wrapper clients to complete.  
178 - * The interface mutex is not locked by this method.  
179 - * \param clients - Vector with client wrapper pointers that need to be waited on.  
180 - * \param[in,out] waitFor - The number of milliseconds to wait for completetion of all commands.  
181 - * On return waitFor contains the time left.  
182 - * \param tokens - The tokens to wait for. An empty set means to wait for all commands  
183 - * on all clients to complete.  
184 - * \return True when all commands have completed in time or false if not.  
185 - */  
186 - bool waitForCompletionInternalClients(const std::vector<IMqttClientImpl*>& clients, std::chrono::milliseconds& waitFor, const std::set<Token>& tokens) const;  
187 -  
188 - /**  
189 - * @brief Determine the state of this client based on the connection statusses of its client wrappers.  
190 - * The states this client can communicate are:  
191 - * Unknown : When at least one wrapper is in a different state then Connected or ReconnectInProgress or when no wrappers are available.  
192 - * Good : When all wrappers are connected.  
193 - * ConnectionFailure : When at least one wrapper attempts reconnection.  
194 - * Unregister : When the serverstate instance is destroyed.  
195 - *  
196 - * The other states are about the information providers to the mqtt broker (the publishers) and we cannot say anything about them here.  
197 - * The state "Good" is the exception. This state means in this case that this clients connection is ok and not that the underlying data  
198 - * source (publisher) is ok.  
199 - *  
200 - * @param connectionStates A vector with the connection statusses of all client wrappers.  
201 - */  
202 - StateEnum determineState(const std::vector<ConnectionStatus>& connectionStates);  
203 -  
204 - /**  
205 - * @brief Add an event to the synchronized queue.  
206 - * @param ev A function object that performs work in the context of this class.  
207 - */  
208 - void pushEvent(std::function<void()> ev);  
209 -  
210 - /**  
211 - * @brief Worker method that executes the events.  
212 - */  
213 - void eventHandler();  
214 -  
215 - mutable std::mutex m_interfaceMutex; ///< Makes the interface mutual exclusive  
216 - mutable std::mutex m_internalMutex; ///< Protect the internal state.  
217 - std::string m_endpoint; ///< The endpoint uri.  
218 - std::string m_clientId; ///< The main client identification.  
219 - std::set<Token> m_activeTokens; ///< Set with active command tokens. Callbacks still need to be made for these tokens.  
220 - mutable std::condition_variable m_activeTokensCV; ///< Wait on a condition to become true w.r.t. the active token set.  
221 - std::function<void(const Token&)> m_deliveryCompleteCallback; ///< Optional callback for publish completion.  
222 - ServerState m_serverState; ///< Records the state of the connection to the broker that this client is connected to.  
223 - std::unique_ptr<IMqttClientImpl> m_principalClient; ///< The main wrapper client.  
224 - std::vector<std::unique_ptr<IMqttClientImpl>> m_additionalClients; ///< A vector of additional wrapper clients.  
225 - SynchronizedQueue<std::function<void()>> m_eventQueue; ///< Synchronized queue for scheduling additional work.  
226 - std::thread m_workerThread; ///< A worker thread that is used to perform actions that cannot be done on the callback threads.  
227 -};  
228 -  
229 -} // End namespace mqtt  
230 -} // End namespace components  
231 -} // End namespace osdev  
232 -  
233 -#endif // OSDEV_COMPONENTS_MQTT_MQTTCLIENT_H  
src/mqttfailure.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MQTTFAILURE_H  
23 -#define OSDEV_COMPONENTS_MQTT_MQTTFAILURE_H  
24 -  
25 -// std  
26 -#include <string>  
27 -  
28 -// paho  
29 -#include <MQTTAsync.h>  
30 -  
31 -namespace osdev {  
32 -namespace components {  
33 -namespace mqtt {  
34 -  
35 -/*!  
36 - * \brief Class for paho mqtt failure response data.  
37 - */  
38 -class MqttFailure  
39 -{  
40 -public:  
41 - /*!  
42 - * \brief Construct MqttFailure instance by copying information from the paho failure struct.  
43 - * \param data Paho response failure data.  
44 - */  
45 - explicit MqttFailure(const MQTTAsync_failureData* data);  
46 -  
47 - /*!  
48 - * \return The command token  
49 - */  
50 - MQTTAsync_token token() const { return m_token; }  
51 -  
52 - /*!  
53 - * \return The failure code.  
54 - */  
55 - int code() const { return m_code; }  
56 -  
57 - /*!  
58 - * \return The failure message.  
59 - * \retval "no message" when no message is available.  
60 - */  
61 - const std::string& message() const { return m_message; }  
62 -  
63 - /*!  
64 - * \return string interpretation of the code.  
65 - * \note negative codes are interpreted as paho error codes.  
66 - */  
67 - std::string codeToString() const;  
68 -  
69 -private:  
70 - MQTTAsync_token m_token; ///< Command token.  
71 - int m_code; ///< Failure code.  
72 - std::string m_message; ///< Optional message. Equal to "no message" when message is not available.  
73 -};  
74 -  
75 -} // End namespace mqtt  
76 -} // End namespace components  
77 -} // End namespace osdev  
78 -  
79 -#endif // OSDEV_COMPONENTS_MQTT_MQTTFAILURE_H  
src/mqttidgenerator.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MLOGICIDGENERATOR_H  
23 -#define OSDEV_COMPONENTS_MQTT_MLOGICIDGENERATOR_H  
24 -  
25 -// std  
26 -#include <string>  
27 -  
28 -// osdev::components::mqtt  
29 -#include "commondefs.h"  
30 -  
31 -namespace osdev {  
32 -namespace components {  
33 -namespace mqtt {  
34 -  
35 -class MqttIdGenerator  
36 -{  
37 -public:  
38 - /**  
39 - * @brief Generates a new MqttId, which is guaranteed to be unique.  
40 - * @return A new unique MqttId.  
41 - */  
42 - static MqttId generate();  
43 -  
44 - /**  
45 - * @brief Returns an MqttId that represents null.  
46 - * @return An MqttId that represents null.  
47 - */  
48 - static MqttId nullId();  
49 -  
50 - /**  
51 - * @brief Returns an MqttId based on a namespace uuid and a given string.  
52 - * @param namespaceUuid The namespace in which the MqttId is generated.  
53 - * @param name The name for which an MqttId is generated.  
54 - */  
55 - static MqttId nameId(MqttId namespaceUuid, const std::string& name);  
56 -  
57 - /**  
58 - * @brief Returns an MqttId in the MQTT namespace for a given string.  
59 - * @param name The name for which an MqttId is generated.  
60 - */  
61 - static MqttId nameId(const std::string& name);  
62 -};  
63 -  
64 -} // End namespace mqtt  
65 -} // End namespace components  
66 -} // End namespace osdev  
67 -  
68 -#endif // OSDEV_COMPONENTS_MQTT_MLOGICIDGENERATOR_H  
src/mqttmessage.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MQTTMESSAGE_H  
23 -#define OSDEV_COMPONENTS_MQTT_MQTTMESSAGE_H  
24 -  
25 -// std  
26 -#include <string>  
27 -  
28 -// paho-c  
29 -#include <MQTTAsync.h>  
30 -  
31 -namespace osdev {  
32 -namespace components {  
33 -namespace mqtt {  
34 -  
35 -/*!  
36 - * @brief Class for paho mqtt message data  
37 - */  
38 -class MqttMessage  
39 -{  
40 -public:  
41 - /*!  
42 - * @brief Construct empty MqttMessage instance  
43 - */  
44 - MqttMessage();  
45 -  
46 - /*!  
47 - * @brief Construct MqttMessage instance by copying information gfrom the paho message struct  
48 - * @param topic - Paho topic data (copied)  
49 - * @param msg - Paho message data (copied)  
50 - */  
51 - MqttMessage( const std::string &topic, const MQTTAsync_message &msg );  
52 -  
53 - /*!  
54 - * @brief Construct MqttMessage instance.  
55 - * @param topic - Topic String  
56 - * @param retainedFlag - Flag that indicates if message is retained  
57 - * @param duplicateFlag - Flag that indicates if message is duplicate.  
58 - * @param thePayload - The message itself.  
59 - */  
60 - MqttMessage( const std::string &topic, bool retainedFlag, bool duplicateFlag, std::string thePayload );  
61 -  
62 - /*! @return The retained flag value. */  
63 - bool retained() const { return m_retained; }  
64 -  
65 - /*! @return The duplicate flag value */  
66 - bool duplicate() const { return m_duplicate; }  
67 -  
68 - /*! @return The topic on which the message is received. */  
69 - const std::string& topic() const { return m_topic; }  
70 -  
71 - /*! @return The message payload. */  
72 - const std::string& payload() const { return m_payload; }  
73 -  
74 - /*! @return This instance as a paho message */  
75 - MQTTAsync_message toAsyncMessage() const;  
76 -  
77 -private:  
78 - bool m_retained; ///< Retained flag. Not all brokers communicate this flag correctly. (emqx does not, mosquitto does.)  
79 - bool m_duplicate; ///< Duplicate flag ( for qos 1? )  
80 - std::string m_topic; ///< The topic on which the message is recieved.  
81 - std::string m_payload; ///< The actual message data.  
82 -};  
83 -  
84 -  
85 -} // End namespace mqtt  
86 -} // End namespace components  
87 -} // End namespace osdev  
88 -  
89 -#endif // OSDEV_COMPONENTS_MQTT_MQTTMESSAGE_H  
src/mqttstream.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MQTTSTREAM_H  
23 -#define OSDEV_COMPONENTS_MQTT_MQTTSTREAM_H  
24 -  
25 -// This header is used in conjunction with mlogic/commmon/stringify.h to get output streaming of stl container types.  
26 -// The streaming operators are not suitable for marshalling because type information is lost!  
27 -  
28 -// std  
29 -#include <array>  
30 -#include <list>  
31 -#include <map>  
32 -#include <ostream>  
33 -#include <set>  
34 -#include <string>  
35 -#include <vector>  
36 -  
37 -namespace osdev {  
38 -namespace components {  
39 -namespace mqtt {  
40 -  
41 -/**  
42 - * @brief Streams a container with content for which stream operators are available.  
43 - * @note This function is meant for printing and not for marshalling!  
44 - * @tparam Open The container opening character.  
45 - * @tparam Close The container closing character.  
46 - * @tparam T The container type.  
47 - * @param os The stream to use.  
48 - * @param rhs The container that is to be streamed.  
49 - * @param sep The field separator. Default is ", "  
50 - * @return reference to the stream object.  
51 - */  
52 -template <char Open, char Close, typename T>  
53 -std::ostream& streamContainer(std::ostream& os, const T& rhs, const std::string& sep = ", ")  
54 -{  
55 - os << Open;  
56 - for (auto cit = rhs.cbegin(); rhs.cend() != cit; ++cit) {  
57 - os << *cit;  
58 - if (std::next(cit) != rhs.end()) {  
59 - os << sep;  
60 - }  
61 - }  
62 - os << Close;  
63 -  
64 - return os;  
65 -}  
66 -  
67 -} // End namespace mqtt  
68 -} // End namespace components  
69 -} // End namespace osdev  
70 -  
71 -namespace std {  
72 -  
73 -/**  
74 - * @brief Streams a list that contains values for which an output stream operator is available.  
75 - */  
76 -template <typename T>  
77 -std::ostream& operator<<(std::ostream& os, const std::list<T>& rhs)  
78 -{  
79 - return osdev::components::mqtt::streamContainer<'<', '>'>(os, rhs);  
80 -}  
81 -  
82 -/**  
83 - * @brief Streams an array that contains values for which an output stream operator is available.  
84 - */  
85 -template <typename T, std::size_t N>  
86 -std::ostream& operator<<(std::ostream& os, const std::array<T, N>& rhs)  
87 -{  
88 - return osdev::components::mqtt::streamContainer<'[', ']'>(os, rhs);  
89 -}  
90 -  
91 -/**  
92 - * @brief Streams a vector that contains values for which an output stream operator is available.  
93 - */  
94 -template <typename T>  
95 -std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs)  
96 -{  
97 - return osdev::components::mqtt::streamContainer<'[', ']'>(os, rhs);  
98 -}  
99 -  
100 -/**  
101 - * @brief Streams a set that contains values for which an output stream operator is available.  
102 - */  
103 -template <typename T>  
104 -std::ostream& operator<<(std::ostream& os, const std::set<T>& rhs)  
105 -{  
106 - return osdev::components::mqtt::streamContainer<'{', '}'>(os, rhs);  
107 -}  
108 -  
109 -/**  
110 - * @brief Streams a map that contains keys and values for which an output stream operator is available.  
111 - */  
112 -template <typename TKey, typename TValue>  
113 -std::ostream& operator<<(std::ostream& os, const std::map<TKey, TValue>& rhs)  
114 -{  
115 - return osdev::components::mqtt::streamContainer<'{', '}'>(os, rhs);  
116 -}  
117 -  
118 -/**  
119 - * @brief Streams a pair that contains values for which an output stream operator is available.  
120 - */  
121 -template <typename TFirst, typename TSecond>  
122 -std::ostream& operator<<(std::ostream& os, const std::pair<TFirst, TSecond>& rhs)  
123 -{  
124 - os << "{" << rhs.first << " : " << rhs.second << "}";  
125 - return os;  
126 -}  
127 -  
128 -} // End namespace std  
129 -  
130 -#endif // OSDEV_COMPONENTS_MQTT_MQTTSTREAM_H  
src/mqttsubscriberbase.cpp
  1 +/* ****************************************************************************
  2 + * Copyright 2019 Open Systems Development BV *
  3 + * *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a *
  5 + * copy of this software and associated documentation files (the "Software"), *
  6 + * to deal in the Software without restriction, including without limitation *
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  8 + * and/or sell copies of the Software, and to permit persons to whom the *
  9 + * Software is furnished to do so, subject to the following conditions: *
  10 + * *
  11 + * The above copyright notice and this permission notice shall be included in *
  12 + * all copies or substantial portions of the Software. *
  13 + * *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  20 + * DEALINGS IN THE SOFTWARE. *
  21 + * ***************************************************************************/
  22 +#include "mqttclient.h"
  23 +#include "mqttsubscriberbase.h"
  24 +#include "mqttmessage.h"
  25 +#include "credentials.h"
  26 +
  27 +MqttSubscriberBase::MqttSubscriberBase( const std::string &client_id )
  28 + : m_mqtt_client( client_id )
  29 +{
  30 +
  31 +}
  32 +
  33 +std::string MqttSubscriberBase::getClientId() const
  34 +{
  35 + return m_mqtt_client.clientId();
  36 +}
  37 +
  38 +void MqttSubscriberBase::connect(const std::string &hostname, int portnumber,
  39 + const std::string &username, const std::string &password)
  40 +{
  41 + m_mqtt_client.connect( hostname, portnumber, osdev::components::mqtt::Credentials( username, password ) );
  42 +}
  43 +
  44 +void MqttSubscriberBase::subscribe( const std::string &message_topic )
  45 +{
  46 + m_mqtt_client.subscribe( message_topic, 1, [this]( const osdev::components::mqtt::MqttMessage &message )
  47 + {
  48 + this->receive_data( message.topic(), message.payload() );
  49 + });
  50 +}
  51 +
  52 +void MqttSubscriberBase::disconnect()
  53 +{
  54 + m_mqtt_client.disconnect();
  55 +}
src/mqttsuccess.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MQTTSUCCESS_H  
23 -#define OSDEV_COMPONENTS_MQTT_MQTTSUCCESS_H  
24 -  
25 -// std  
26 -#include <string>  
27 -#include <vector>  
28 -  
29 -// boost  
30 -#include <boost/variant.hpp>  
31 -  
32 -// paho  
33 -#include <MQTTAsync.h>  
34 -  
35 -// osdev::components::mqtt  
36 -#include "mqttmessage.h"  
37 -  
38 -namespace osdev {  
39 -namespace components {  
40 -namespace mqtt {  
41 -  
42 -/**  
43 - * @brief Class that holds paho connection data which is returned in the connect response.  
44 - */  
45 -class ConnectionData  
46 -{  
47 -public:  
48 - /*!  
49 - * \brief Construct an empty ConnectData instance.  
50 - */  
51 - ConnectionData();  
52 -  
53 - /*!  
54 - * \brief Construct ConnectData based on incoming values from paho.  
55 - * \param serverUri - The serverUri to which the connection is made (needs to be copied).  
56 - * \param mqttVersion - The mqtt version used by the broker.  
57 - * \param sessionPresent - Flag that indicates if a session was present for the given clientId.  
58 - */  
59 - ConnectionData(char* serverUri, int mqttVersion, int sessionPresent);  
60 -  
61 - /*!  
62 - * \return The server uri.  
63 - */  
64 - const std::string& serverUri() const { return m_serverUri; }  
65 -  
66 - /*!  
67 - * \return The mqtt version.  
68 - */  
69 - int mqttVersion() const { return m_mqttVersion; }  
70 -  
71 - /*!  
72 - * \return if a session was present for the given clientId.  
73 - */  
74 - bool sessionPresent() const { return m_sessionPresent; }  
75 -  
76 -private:  
77 - std::string m_serverUri; ///< The broker server uri.  
78 - int m_mqttVersion; ///< The mqtt version used by the broker.  
79 - bool m_sessionPresent; ///< Flag that indicates whether a session was present for the client id used in the connect.  
80 -};  
81 -  
82 -struct Unspecified  
83 -{  
84 -};  
85 -  
86 -/*!  
87 - * \brief Class for paho mqtt success response data.  
88 - * The paho success response data uses a union and can have different information depending on the command.  
89 - */  
90 -class MqttSuccess  
91 -{  
92 -public:  
93 - /*!  
94 - * \brief Response data for commands without specific data.  
95 - * \param token The token that identifies to which command this response belongs.  
96 - */  
97 - explicit MqttSuccess(MQTTAsync_token token);  
98 -  
99 - /*!  
100 - * \brief Response data for a subscribe command.  
101 - * \param token The token that identifies to which command this response belongs.  
102 - * \param qos Actual quality of service of the subscription.  
103 - */  
104 - MqttSuccess(MQTTAsync_token token, int qos);  
105 -  
106 - /*!  
107 - * \brief Response data for a subscribe many command.  
108 - * \param token The token that identifies to which command this response belongs.  
109 - * \param qosMany Actual quality of service of the subscription for each topic filter.  
110 - */  
111 - MqttSuccess(MQTTAsync_token token, const std::vector<int>& qosMany);  
112 -  
113 - /*!  
114 - * \brief Response data for a publish command.  
115 - * \param token The token that identifies to which command this response belongs.  
116 - * \param pubMsg The message that was published.  
117 - */  
118 - MqttSuccess(MQTTAsync_token token, const MqttMessage& pubMsg);  
119 -  
120 - /*!  
121 - * \brief Response data for a connect command.  
122 - * \param token The token that identifies to which command this response belongs.  
123 - * \param connData The connection data.  
124 - */  
125 - MqttSuccess(MQTTAsync_token token, const ConnectionData& connData);  
126 -  
127 - /*!  
128 - * \return the command token.  
129 - */  
130 - MQTTAsync_token token() const { return m_token; }  
131 -  
132 - /*!  
133 - * \return the qos  
134 - * \throw exception when command is not a subscribe command.  
135 - */  
136 - int qos() const;  
137 -  
138 - /*!  
139 - * \return a vector of qos values (matching the topics in the subscribe many command).  
140 - * \throw exception when command is not a subscribe many command.  
141 - */  
142 - std::vector<int> qosMany() const;  
143 -  
144 - /*!  
145 - * \return Message that has been published.  
146 - * \throw exception when command is not a publish command.  
147 - */  
148 - MqttMessage publishData() const;  
149 -  
150 - /*!  
151 - * return Connection data.  
152 - * throw exception when command is not a connect command.  
153 - */  
154 - ConnectionData connectionData() const;  
155 -  
156 -private:  
157 - MQTTAsync_token m_token; ///< Command token.  
158 - boost::variant<int, std::vector<int>, MqttMessage, ConnectionData, Unspecified> m_data; ///< Data for the various commands.  
159 -};  
160 -  
161 -} // End namespace mqtt  
162 -} // End namespace components  
163 -} // End namespace osdev  
164 -  
165 -#endif // OSDEV_COMPONENTS_MQTT_MQTTSUCCESS_H  
src/mqtttypeconverter.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MLOGICTYPECONVERTER_H  
23 -#define OSDEV_COMPONENTS_MQTT_MLOGICTYPECONVERTER_H  
24 -  
25 -// std  
26 -#include <chrono>  
27 -#include <ctime>  
28 -#include "date.h"  
29 -#include <string>  
30 -  
31 -// boost  
32 -#include <boost/uuid/uuid.hpp>  
33 -  
34 -#include "commondefs.h"  
35 -  
36 -namespace osdev {  
37 -namespace components {  
38 -namespace mqtt {  
39 -  
40 -/**  
41 - * @brief Utility namespace to convert between mqtt common types and other frequently used types.  
42 - */  
43 -namespace MqttTypeConverter {  
44 -  
45 -/**  
46 - * @brief Converts from MqttId to std::string.  
47 - * @param mqttId The mqttId to convert.  
48 - * @return The std::string with contents of the provided mqttId. Format is 12345678-9abc-def0-1234-56789abcdef0.  
49 - */  
50 -std::string toStdString(const MqttId& mqttId);  
51 -  
52 -/**  
53 - * @brief Converts from system clock timepoint to std::string.  
54 - * @tparam Duration std::chrono::duration instance.  
55 - * Duration::Period is used to determine the precision  
56 - * of the subsecond part of the returned ISO8601 string.  
57 - * Uses the duration of the StdTime type by default.  
58 - * @param tp The timepoint to converter.  
59 - * @return ISO8601 string representation of stdTime.  
60 - */  
61 -template <typename Duration>  
62 -std::string toStdString(const std::chrono::time_point<std::chrono::system_clock, Duration>& tp)  
63 -{  
64 - return date::format("%FT%T%Ez", tp);  
65 -}  
66 -  
67 -/**  
68 - * @brief Converts from std::string to MqttId.  
69 - * @param mqttId The MqttId string to convert.  
70 - * @return the converted string to MqttId.  
71 - */  
72 -MqttId toMqttId(const std::string& mqttId);  
73 -  
74 -/**  
75 - * @brief Creates a descriptive string based on the specified input parameters.  
76 - * @param str The prefix of the string.  
77 - * @param mqttId The id of which to use the first 4 characters.  
78 - * @return str + "-" + <first 4 characters of mqttId>  
79 - * Example: "Unassigned-a2c4".  
80 - */  
81 -std::string toShortGuidAppendedString(const std::string& str, const MqttId& mqttId);  
82 -  
83 -/**  
84 - * @brief Converts from PosixTime (time_t) to StdTime.  
85 - * @param posixTime The Posix Time (time_t) to convert.  
86 - * @return The StdTime with same value as the provided posixTime.  
87 - */  
88 -StdTime toStdTime(const std::time_t& posixTime);  
89 -  
90 -/**  
91 - * @brief Converts from StdTime to PosixTime (time_t).  
92 - * @param stdTime The StdTime to convert.  
93 - * @return The PosixTime with the same value as the provided stdTime.  
94 - */  
95 -time_t toPosixTime(const osdev::components::mqtt::StdTime& stdTime);  
96 -  
97 -/**  
98 - * @brief Converts the specified posixTimeString to an OptionalTime.  
99 - * @param posixTimeString A posix time as string.  
100 - * @return The converted posixTimeString.  
101 - * @retval boost::none if the specified posixTimeString could not be converted to a StdTime.  
102 - */  
103 -osdev::components::mqtt::OptionalTime toOptionalTime(const std::string& posixTimeString);  
104 -  
105 -} // End namespace MqttTypeConverter  
106 -} // End namespace mqtt  
107 -} // End namespace components  
108 -} // End namespace osdev  
109 -  
110 -#endif // OSDEV_COMPONENTS_MQTT_MQTTTYPECONVERTER_H  
src/mqttutil.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MQTTUTIL_H  
23 -#define OSDEV_COMPONENTS_MQTT_MQTTUTIL_H  
24 -  
25 -// std  
26 -#include <string>  
27 -  
28 -namespace osdev {  
29 -namespace components {  
30 -namespace mqtt {  
31 -  
32 -/*!  
33 - * \brief Determine if topic is a valid mqtt topic filter.  
34 - * \param topic - The topic to test.  
35 - * \return True when topic is valid, false otherwise.  
36 - */  
37 -bool isValidTopic( const std::string &topic );  
38 -  
39 -/*!  
40 - * \brief Test a topic against another topicfilter for overlap.  
41 - * \param existingTopic - The topic to test against  
42 - * \param newTopic - The topic to test.  
43 - * \return True when topics overlap, false otherwise  
44 - */  
45 -bool testForOverlap( const std::string & existingTopic, const std::string &newTopic );  
46 -  
47 -/*!  
48 - * \brief Test a topic for occurence of wildcards  
49 - * \param topic - The topic to test  
50 - * \return True if topics contains wildcards, false otherwise  
51 - */  
52 -bool hasWildcard( const std::string &topic );  
53 -  
54 -/*!  
55 - * \brief Create a regular expression string based on a topicfilter that can be used  
56 - * to match topic strings against topics with no wildcards.  
57 - * \pre The topic filter is valid.  
58 - * \return The regular expression string. If the topic filter is not valid then the  
59 - * returned string is also not valid.  
60 - */  
61 -std::string convertTopicToRegex( const std::string &topic );  
62 -  
63 -} // End namespace mqtt  
64 -} // End namespace components  
65 -} // osdev  
66 -  
67 -#endif // OSDEV_COMPONENTS_MQTT_MQTTUTIL_H  
src/scopeguard.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_SCOPEGUARD_H  
23 -#define OSDEV_COMPONENTS_MQTT_SCOPEGUARD_H  
24 -  
25 -// std  
26 -#include <functional>  
27 -  
28 -#include "macrodefs.h"  
29 -#include "utils.h"  
30 -  
31 -#define OSDEV_COMPONENTS_SCOPEGUARD(variableName, ...) \  
32 - osdev::components::mqtt::ScopeGuard OSDEV_COMPONENTS_COMBINE(Scope__Guard__##variableName##__, __LINE__)(__VA_ARGS__); \  
33 - osdev::components::mqtt::apply_unused_parameters(OSDEV_COMPONENTS_COMBINE(Scope__Guard__##variableName##__, __LINE__));  
34 -  
35 -namespace osdev {  
36 -namespace components {  
37 -namespace mqtt {  
38 -  
39 -using CleanUpFunction = std::function<void() noexcept>;  
40 -  
41 -/**  
42 - * @brief Ensures that a cleanup function is called at the end of the current scope.  
43 - */  
44 -class ScopeGuard  
45 -{  
46 -public:  
47 - /**  
48 - * @brief Constructs an empty scopeguard.  
49 - * The scopeguard can be set by moving another ScopeGuard into this one.  
50 - */  
51 - ScopeGuard();  
52 -  
53 - /**  
54 - * @brief Constructs a RAII instance that will call cleanupFunc in it's destructor.  
55 - * @param cleanupFunc The cleanup function to call at the end of the current scope.  
56 - * This cleanup function must not throw exceptions. If it does, the behavior is undefined.  
57 - */  
58 - ScopeGuard(const CleanUpFunction& cleanupFunc);  
59 -  
60 - // Movable, not copyable  
61 - ScopeGuard(const ScopeGuard&) = delete;  
62 - ScopeGuard& operator=(const ScopeGuard&) = delete;  
63 - ScopeGuard(ScopeGuard&&) = default;  
64 - ScopeGuard& operator=(ScopeGuard&&) = default;  
65 -  
66 - ~ScopeGuard() noexcept;  
67 -  
68 -private:  
69 - CleanUpFunction m_cleanupFunc;  
70 -};  
71 -  
72 -} // End namespace mqtt  
73 -} // End namespace components  
74 -} // End namespace osdev  
75 -  
76 -#endif // OSDEV_COMPONENTS_MQTT_SCOPEGUARD_H  
src/serverstate.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_SERVERSTATE_H  
23 -#define OSDEV_COMPONENTS_MQTT_SERVERSTATE_H  
24 -  
25 -// std  
26 -#include <atomic>  
27 -#include <map>  
28 -  
29 -// boost  
30 -#include <boost/signals2/connection.hpp>  
31 -  
32 -// osdev::components::mqtt  
33 -#include "istatecallback.h"  
34 -  
35 -namespace osdev {  
36 -namespace components {  
37 -namespace mqtt {  
38 -  
39 -/*!  
40 - * \brief Class for administrating ServerState callbacks.  
41 - * ServiceClientBase uses this object to notify the server state listeners  
42 - * of changes in the serverstate of the server that the client is connected to.  
43 - */  
44 -class ServerState  
45 -{  
46 -public:  
47 - /*!  
48 - * \brief Constructs a ServerState object. This object has a one to one relation with an IStateCallback object.  
49 - * \param stateCallbackIf identification of the interface that generates the signal.  
50 - */  
51 - explicit ServerState(const IStateCallback* stateCallbackIf);  
52 -  
53 - /*!  
54 - * \brief Destroy the ServerState.  
55 - * Calls clearAllStateChangeCallbacks() to unregister itself from the listeners.  
56 - */  
57 - virtual ~ServerState();  
58 -  
59 - // non copyable, non movable  
60 - ServerState(const ServerState&) = delete;  
61 - ServerState& operator=(ServerState&) = delete;  
62 - ServerState(ServerState&&) = delete;  
63 - ServerState& operator=(ServerState&&) = delete;  
64 -  
65 - /*!  
66 - * \brief Registers a statechange callback method.  
67 - * \param cb - The callback method.  
68 - * \return handle that identifies the callback method.  
69 - */  
70 - StateChangeCallbackHandle registerStateChangeCallback(const IStateCallback::SlotStateChange& cb);  
71 -  
72 - /*!  
73 - * \brief Unregisters a state change callback method.  
74 - * \param handle Handle that identifies the callback method.  
75 - */  
76 - void unregisterStateChangeCallback(StateChangeCallbackHandle handle);  
77 -  
78 - /*!  
79 - * \brief Removes all callback methods.  
80 - * An Unregister state is signalled to the listeners.  
81 - */  
82 - void clearAllStateChangeCallbacks();  
83 -  
84 - /*!  
85 - * \brief Emit the State changed signal.  
86 - * \param newState - The new state.  
87 - */  
88 - void emitStateChanged(StateEnum newState);  
89 -  
90 - /*!  
91 - * \brief Return the last state received from server.  
92 - * \return state of server  
93 - */  
94 - StateEnum state() const;  
95 -  
96 - /*!  
97 - * \brief Returns the handle that will be given to the next callback that is registered.  
98 - */  
99 - static StateChangeCallbackHandle nextHandle()  
100 - {  
101 - return s_nextServerStateCallbackHandle;  
102 - }  
103 -  
104 -private:  
105 - /*!  
106 - * Type for holding connections to server state callback functions.  
107 - */  
108 - using ServerStateCallbackMap = std::map<StateChangeCallbackHandle, boost::signals2::scoped_connection>;  
109 -  
110 - IStateCallback::SigStateChange sig_serverStateChanged; ///< Signal emitted when server state has changed.  
111 -  
112 - const IStateCallback* m_stateCallbackIf; ///< Identification of the the interface that generates the signal (not owned)  
113 - ServerStateCallbackMap m_serverStateCallbackMap; ///< Map with serverstate callback connections.  
114 -  
115 - static std::atomic<StateChangeCallbackHandle> s_nextServerStateCallbackHandle; ///< Handle given to next serverstate callback registration (0 is not valid).  
116 -  
117 - StateEnum m_state; ///< Store the last state received from the server.  
118 -  
119 - /*!  
120 - * \return The clientId of the IStateCallback interface, or "null" if it is nullptr.  
121 - */  
122 - std::string stateCallbackClientId() const;  
123 -  
124 - static const std::string s_identifier;  
125 -};  
126 -  
127 -} // End namespace mqtt  
128 -} // End namespace components  
129 -} // End namespace osdev  
130 -  
131 -#endif // OSDEV_COMPONENTS_MQTT_SERVERSTATE_H  
src/sharedreaderlock.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_SHAREDREADERLOCK_H  
23 -#define OSDEV_COMPONENTS_MQTT_SHAREDREADERLOCK_H  
24 -  
25 -// std  
26 -#include <condition_variable>  
27 -#include <map>  
28 -#include <mutex>  
29 -#include <thread>  
30 -  
31 -// mlogic::common  
32 -#include "scopeguard.h"  
33 -  
34 -namespace osdev {  
35 -namespace components {  
36 -namespace mqtt {  
37 -  
38 -#define OSDEV_COMPONENTS_SHAREDLOCK_SCOPE(lockvar) \  
39 - lockvar.lockShared(); \  
40 - OSDEV_COMPONENTS_SCOPEGUARD(lockvar, [&]() { lockvar.unlock(); });  
41 -  
42 -#define OSDEV_COMPONENTS_EXCLUSIVELOCK_SCOPE(lockvar) \  
43 - lockvar.lockExclusive(); \  
44 - OSDEV_COMPONENTS_SCOPEGUARD(lockvar, [&]() { lockvar.unlock(); });  
45 -  
46 -/**  
47 - * @brief Class is used to administrate the lock data.  
48 - */  
49 -class LockData  
50 -{  
51 -public:  
52 - /**  
53 - * @brief Default constructable. Lock is not active and the count is 0.  
54 - */  
55 - LockData()  
56 - : m_count(0)  
57 - , m_active(false)  
58 - {  
59 - }  
60 -  
61 - // Copyable, movable  
62 - LockData(const LockData&) = default;  
63 - LockData& operator=(const LockData&) = default;  
64 - LockData(LockData&&) = default;  
65 - LockData& operator=(LockData&&) = default;  
66 -  
67 - /**  
68 - * @return true when the lock is active, false otherwise.  
69 - * @note A lock becomes active the first time that increase() is called.  
70 - */  
71 - inline bool active() const  
72 - {  
73 - return m_active;  
74 - }  
75 -  
76 - /**  
77 - * @brief Increases the lock count by one.  
78 - * An inactive lock becomes active by this call.  
79 - */  
80 - inline void increase()  
81 - {  
82 - m_active = true;  
83 - ++m_count;  
84 - }  
85 -  
86 - /**  
87 - * @brief Decreases the lock count by one.  
88 - * The count is only decreased for active locks. When the lock count becomes 0 the lock  
89 - * is deactivated.  
90 - * @return true when the lock is still active after decrease and false when it is deactivated.  
91 - */  
92 - inline bool decrease()  
93 - {  
94 - if (m_active) {  
95 - --m_count;  
96 - m_active = (0 != m_count);  
97 - }  
98 - return m_active;  
99 - }  
100 -  
101 - /**  
102 - * @brief Conversion operator that returns the lock count.  
103 - */  
104 - inline operator std::size_t() const  
105 - {  
106 - return m_count;  
107 - }  
108 -  
109 - /**  
110 - * @brief Static method for initializing a lock data based on already existing lock data.  
111 - * The new lock data is not active.  
112 - * @note This is used to promote a shared lock to an exclusive lock.  
113 - */  
114 - inline static LockData initialize(const LockData& other)  
115 - {  
116 - auto newLockData(other);  
117 - newLockData.m_active = false;  
118 - return newLockData;  
119 - }  
120 -  
121 -private:  
122 - std::size_t m_count; ///< The lock count.  
123 -  
124 - /**  
125 - * @brief Flag to indicate whether the lock is active.  
126 - * This flag is necessary because when the lock is promoted  
127 - * the lock count is not zero but the lock still should be activated again.  
128 - */  
129 - bool m_active;  
130 -};  
131 -  
132 -/**  
133 - * @brief Lock class that allows multiple readers to own the lock in a shared way.  
134 - * A writer will want exclusive ownership so that it can mutate the content that  
135 - * is protected by this lock.  
136 - *  
137 - * Reader and writer should be interpreted as to how threads interact with the content that this lock protects. It is up  
138 - * to the caller to enforce the correct behaviour. In other words don't take a shared lock and change the content!  
139 - *  
140 - * The administration of this class uses the std::thread::id to register which thread holds what kind of lock.  
141 - * This id is reused, so be really careful to pair each lock with an unlock, otherwise newly spawned threads might  
142 - * end up having a lock without taking one.  
143 - */  
144 -class SharedReaderLock  
145 -{  
146 -public:  
147 - /**  
148 - * Default constructable.  
149 - * The lock is not locked.  
150 - */  
151 - SharedReaderLock();  
152 -  
153 - /**  
154 - * Destructor will throw when there are threads registered.  
155 - */  
156 - ~SharedReaderLock();  
157 -  
158 - // Non copyable, non movable  
159 - SharedReaderLock(const SharedReaderLock&) = delete;  
160 - SharedReaderLock& operator=(const SharedReaderLock&) = delete;  
161 - SharedReaderLock(SharedReaderLock&&) = delete;  
162 - SharedReaderLock& operator=(SharedReaderLock&&) = delete;  
163 -  
164 - /**  
165 - * @brief Lock in a shared way. For read only operations.  
166 - * Multiple threads can have shared ownership on this lock.  
167 - * It is guaranteed that a call to lockExclusive will wait until all read locks are unlocked.  
168 - * When a call to lockExclusive is made and is waiting, no new reader locks are accepted.  
169 - * A thread that owns a shared lock can lock again. The lock will be unlocked for this thread when as many unlock calls are made.  
170 - * A thread that owns a shared lock can upgrade the lock to an exclusive lock by calling lockExclusive. The thread has to wait  
171 - * for exclusive ownership and has the exclusive lock until all unlocks are made (if it had done multiple shared locks before an exclusive lock).  
172 - */  
173 - void lockShared();  
174 -  
175 - /**  
176 - * @brief Lock in an exclusive way. For write operations.  
177 - * Only one thread can have exclusive ownership of this lock.  
178 - * While a thread waits for exlusive ownership shared locks are denied. This lock is unfair in the  
179 - * sense that it favours write locks.  
180 - * A thread that owns exclusive ownership can make another exclusive lock or a even a shared lock. Both are  
181 - * treated as an exclusive lock that updates the lock count. As many unlocks need to be called to unlock the exclusive lock.  
182 - */  
183 - void lockExclusive();  
184 -  
185 - /**  
186 - * @brief Unlock the lock. The thread id is used to determine which lock needs to be unlocked.  
187 - * If a thread does not own this lock at all then nothing happens.  
188 - */  
189 - void unlock();  
190 -  
191 -private:  
192 - std::mutex m_mutex; ///< Mutex that protects the lock administration.  
193 - std::map<std::thread::id, LockData> m_readLockMap; ///< Map with read lock data.  
194 - std::map<std::thread::id, LockData> m_writeLockMap; ///< Map with write lock data.  
195 -  
196 - std::condition_variable m_readersCV; ///< lockShared waits on this condition variable.  
197 - std::condition_variable m_writersCV; ///< lockExclusive waits on this condition variable.  
198 -};  
199 -  
200 -} // End namespace mqtt  
201 -} // End namespace components  
202 -} // End namespace osdev  
203 -  
204 -#endif // OSDEV_COMPONENTS_MQTT_SHAREDREADERLOCK_H  
src/stringify.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDSEV_COMPONENTS_MQTT_STRINGIFY_H  
23 -#define OSDSEV_COMPONENTS_MQTT_STRINGIFY_H  
24 -  
25 -// std  
26 -#include <sstream>  
27 -  
28 -// osdev::components::mqtt  
29 -#include "mqttstream.h"  
30 -  
31 -namespace osdev {  
32 -namespace components {  
33 -namespace mqtt {  
34 -  
35 -/**  
36 - * @brief Stringifies all objects for which an output stream operator is available.  
37 - * @note This method is meant to be used for printing and not for marshalling!  
38 - * @tparam T The object type.  
39 - * @param value The value to stringify.  
40 - * @return stringified value.  
41 - */  
42 -template <typename T>  
43 -std::string toString(const T& value)  
44 -{  
45 - std::ostringstream oss;  
46 - oss << value;  
47 - return oss.str();  
48 -}  
49 -  
50 -} // End namespace mqtt  
51 -} // End namespace components  
52 -} // End namespace osdev  
53 -  
54 -#endif // OSDEV_COMPONENTS_MQTT_STRINGIFY_H  
src/stringutils.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_STRINGUTILS_H  
23 -#define OSDEV_COMPONENTS_MQTT_STRINGUTILS_H  
24 -  
25 -// See boost/algorithm/string.hpp for more string utility functions  
26 -  
27 -// std  
28 -#include <sstream>  
29 -#include <string>  
30 -#include <vector>  
31 -  
32 -namespace osdev {  
33 -namespace components {  
34 -namespace mqtt {  
35 -  
36 -/**  
37 - * @brief Removes characters from the specified string. Modifies the specified string in place.  
38 - * @param str The string to modify.  
39 - * @param charsToRemove The characters to remove from str.  
40 - */  
41 -void removeCharsFromStringInPlace(std::string& str, const std::string& charsToRemove);  
42 -  
43 -/**  
44 - * @brief Determines whether the specified string is all digits.  
45 - * @param str The string for which to determine if it's numeric.  
46 - * @return True if the specified string is numeric; otherwise, false.  
47 - */  
48 -bool is_numeric(const std::string& str);  
49 -  
50 -} // End namespace mqtt  
51 -} // End namespace components  
52 -} // End namespace osdev  
53 -  
54 -#endif // OSDEV_COMPONENTS_MQTT_STRINGUTILS_H  
src/synchronizedqueue.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_SYNCHRONIZEDQUEUE_H  
23 -#define OSDEV_COMPONENTS_MQTT_SYNCHRONIZEDQUEUE_H  
24 -  
25 -// std  
26 -#include <atomic>  
27 -#include <condition_variable>  
28 -#include <memory>  
29 -#include <mutex>  
30 -#include <queue>  
31 -#include <string>  
32 -#include <type_traits>  
33 -  
34 -// osdev::components::mqtt  
35 -#include "lockguard.h"  
36 -#include "metaprogrammingdefs.h"  
37 -  
38 -namespace osdev {  
39 -namespace components {  
40 -namespace mqtt {  
41 -  
42 -OSDEV_COMPONENTS_HASMETHOD_TRAIT(capacity, )  
43 -  
44 -/*!  
45 - * \brief Generic Queue template for defining a thin  
46 - * wrapper around std::queue to make overflow detection possible.  
47 - * This template has no definition and will lead to a compile  
48 - * time error when it is chosen.  
49 - */  
50 -template <typename T, typename C, typename enable = void>  
51 -class Queue;  
52 -  
53 -/*!  
54 - * \brief A specialization when the underlying container has a capacity method.  
55 - * To detect overflow the capacity of the underlying container is needed.  
56 - * Not all containers have a capacity.  
57 - * When the capacity method is not available SFINAE will discard this template.  
58 - */  
59 -template <typename T, typename C>  
60 -class Queue<T, C, typename std::enable_if<has_capacity<C>::value>::type> : public std::queue<T, C>  
61 -{  
62 -public:  
63 - using size_type = typename std::queue<T, C>::size_type;  
64 -  
65 - typename C::size_type capacity() const  
66 - {  
67 - return this->c.capacity();  
68 - }  
69 -};  
70 -  
71 -/*!  
72 - * \brief A specialization for when the underlying container does not support a capacity  
73 - * In this case max_size is returned which results in overflow not being detected.  
74 - */  
75 -template <typename T, typename C>  
76 -class Queue<T, C, typename std::enable_if<!has_capacity<C>::value>::type> : public std::queue<T, C>  
77 -{  
78 -public:  
79 - using size_type = typename std::queue<T, C>::size_type;  
80 - typename C::size_type capacity() const  
81 - {  
82 - return this->c.max_size();  
83 - }  
84 -};  
85 -  
86 -/*!  
87 - * \brief Represents a synchronized queue  
88 - * @tparam T The type of the items in the queue  
89 - * @tparam C The underlying character. The container must satisfy the  
90 - * requirements of a SequenceContainer.  
91 - * Addittionally container must supply a pop_front and a max_size method.  
92 - *  
93 - * The underlying container determines the overflow behaviour.  
94 - * A circular buffer leads to a lossy queue that drops items when the  
95 - * queue is full while a std::deque will never overflow.  
96 - *  
97 - * The queue has the following states: started, paused, stopped.  
98 - * In the started state the queue acceptsincoming items and it allows items  
99 - * to be popped when data is available.  
100 - * In the paused state incoming items are allowed. The pop method will  
101 - * block until the queue is unpaused or stopped.  
102 - * In the stopped state incoming items are not allowed and dropped.  
103 - * The pop method will return false.  
104 - */  
105 -template <typename T, typename C = std::deque<T>>  
106 -class SynchronizedQueue  
107 -{  
108 -public:  
109 - using QueueType = Queue<T, C>;  
110 -  
111 - /*!  
112 - * \brief Constructs an empty queue  
113 - * \param id - Identification string for this queue ( used in logging ).  
114 - * \param paused - The state in which to setup the queue ( pause or active),  
115 - * ( Default is active )  
116 - */  
117 - explicit SynchronizedQueue( const std::string &id, bool paused = false )  
118 - : m_id( id )  
119 - , m_queueMutex()  
120 - , m_dataAvailableOrStopCV()  
121 - , m_queue()  
122 - , m_stop( false )  
123 - , m_pause( paused )  
124 - , m_numOverflows( 0 )  
125 - {}  
126 -  
127 - /*!  
128 - * \brief Stops the queue on destruction  
129 - */  
130 - ~SynchronizedQueue()  
131 - {  
132 - this->stop();  
133 - }  
134 -  
135 - /*!  
136 - * @brief Pushes the item in the queue  
137 - * @tparam TItem - The cv qualified type of the value to push.  
138 - * In a stopped state the queue drops incoming data.  
139 - * In a paused / active state the queue accepts incoming data.  
140 - * @tparam item - The item to push to the queue.  
141 - */  
142 - template <typename TItem>  
143 - void push(TItem &&item)  
144 - {  
145 - OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC( m_queueMutex, m_id );  
146 - if( m_stop )  
147 - {  
148 - return;  
149 - }  
150 -  
151 - if( m_queue.capacity() == m_queue.size() )  
152 - {  
153 - if( m_numOverflows++ % 100 == 0 )  
154 - {  
155 - // Log a warning that there is a number of overflows.  
156 - }  
157 - }  
158 - m_queue.push( std::forward<TItem>(item) );  
159 - OSDEV_COMPONENTS_UNIQUELOCK_UNLOCK_SPECIFIC(m_queueMutex, m_id);  
160 - m_dataAvailableOrStopCV.notify_one();  
161 - }  
162 -  
163 - /*!  
164 - * @brief pop - Pops an item from the queue. This method blocks when te state is paused or when there is no data available.  
165 - * @param item - The item to which to copy the popped item.  
166 - * @return True if an item was popped: otherwise false  
167 - */  
168 - bool pop(T& item)  
169 - {  
170 - OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC( m_queueMutex, m_id );  
171 - m_dataAvailableOrStopCV.wait(OSDEV_COMPONENTS_UNIQUELOCK(m_queueMutex), [this]()  
172 - { return ((this->m_queue.size() > 0 && !m_pause) || this->m_stop); });  
173 - if( m_stop )  
174 - {  
175 - return false;  
176 - }  
177 - item = std::move(m_queue.front());  
178 - m_queue.pop();  
179 - return true;  
180 - }  
181 -  
182 - bool pop(std::vector<T> &items)  
183 - {  
184 - OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC( m_queueMutex, m_id );  
185 - m_dataAvailableOrStopCV.wait(OSDEV_COMPONENTS_UNIQUELOCK(m_queueMutex), [this]()  
186 - { return ((this->m_queue.size() > 0 && !m_pause) || this->m_stop); });  
187 - if( m_stop )  
188 - {  
189 - return false;  
190 - }  
191 - items.clear();  
192 - items.reserve(m_queue.size());  
193 - while( m_queue.size() > 0 )  
194 - {  
195 - items.emplace_back(std::move(m_queue.front() ) );  
196 - m_queue.pop();  
197 - }  
198 - return true;  
199 - }  
200 -  
201 - /*!  
202 - * \return The current size of the queue  
203 - */  
204 - typename QueueType::size_type size() const  
205 - {  
206 - OSDEV_COMPONENTS_LOCKGUARD_SPECIFIC(m_queueMutex, m_id);  
207 - return m_queue.size();  
208 - }  
209 -  
210 -  
211 - /*!  
212 - * \brief Start the Queue  
213 - * The queue is only started when it is in a stopped state.  
214 - * \param paused - If true, the queue will be started in a paused  
215 - * state which means that no items will be popped.  
216 - */  
217 - void start(bool paused)  
218 - {  
219 - // Reason that a lock is used: See documentation of std::condition_variable  
220 - //  
221 - // Even is the shared variable is atomic (m_stop in this case), it must be modified under the mutex  
222 - // in order to correctly publish the modification to the waiting thread.  
223 - //  
224 - OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC(m_queueMutex, m_id);  
225 - if( !m_stop )  
226 - {  
227 - // already started  
228 - return;  
229 - }  
230 - m_stop = false;  
231 - m_pause = paused;  
232 - OSDEV_COMPONENTS_UNIQUELOCK_UNLOCK_SPECIFIC(m_queueMutex, m_id);  
233 - if( !paused )  
234 - {  
235 - m_dataAvailableOrStopCV.notify_all();  
236 - }  
237 - }  
238 -  
239 - /*!  
240 - * \brief Pause or unpause the queue.  
241 - * When the queue is paused no items will be popped.  
242 - * The state is not altered when the queue is stopped.  
243 - * \param value - Flag that indicates whether the queue is paused or unpaused.  
244 - */  
245 - void pause(bool value)  
246 - {  
247 - // Reason that a lock is used: see documentation of std::condition_variable  
248 - //  
249 - // Even if the shared variable is atomic (m_stop in this case), it must be modified under the mutex  
250 - // in order to correctly publish the modification to the waiting thread.  
251 - //  
252 - OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC(m_queueMutex, m_id);  
253 - if (m_stop) {  
254 - return;  
255 - }  
256 - m_pause = value;  
257 - OSDEV_COMPONENTS_UNIQUELOCK_UNLOCK_SPECIFIC(m_queueMutex, m_id);  
258 - if (!value) {  
259 - m_dataAvailableOrStopCV.notify_all();  
260 - }  
261 - }  
262 -  
263 - /*!  
264 - * \brief Stop the queue.  
265 - * The pop method will return a false after calling this method.  
266 - * The queue can be restarted with the start method.  
267 - */  
268 - void stop()  
269 - {  
270 - // Reason that a lock is used: see documentation of std::condition_variable  
271 - //  
272 - // Even if the shared variable is atomic (m_stop in this case), it must be modified under the mutex  
273 - // in order to correctly publish the modification to the waiting thread.  
274 - //  
275 - OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC(m_queueMutex, m_id);  
276 - m_stop = true;  
277 - m_pause = false;  
278 - OSDEV_COMPONENTS_UNIQUELOCK_UNLOCK_SPECIFIC(m_queueMutex, m_id);  
279 - m_dataAvailableOrStopCV.notify_all();  
280 - }  
281 -  
282 - /*!  
283 - * \brief Clears the queue.  
284 - * This method also resets the overflow counter.  
285 - */  
286 - void clear()  
287 - {  
288 - OSDEV_COMPONENTS_LOCKGUARD_SPECIFIC(m_queueMutex, m_id);  
289 - QueueType emptyQueue;  
290 - std::swap(m_queue, emptyQueue);  
291 - m_numOverflows = 0;  
292 - }  
293 -  
294 -private:  
295 - const std::string m_id; ///< Queue identification string  
296 - mutable std::mutex m_queueMutex; ///< Protects access to the queue  
297 - std::condition_variable m_dataAvailableOrStopCV; ///< Provides wait functionality for the queue becoming empty  
298 - QueueType m_queue; ///< Holds the items  
299 - std::atomic_bool m_stop; ///< Flag that indicates whether the queue needs to stop.  
300 - std::atomic_bool m_pause; ///< Flag that indicates whether the queue is paused.  
301 -  
302 - /*!  
303 - * \brief Counts the number of items that the buffer overflows.  
304 - * If the underlying buffer is a ring buffer an overflow  
305 - * means that an item will be overwritten. For a normal  
306 - * sequence container it means that the it is enlarged.  
307 - */  
308 - std::uint32_t m_numOverflows;  
309 -};  
310 -  
311 -  
312 -  
313 -  
314 -  
315 -} // End namespace mqtt  
316 -} // End namespace components  
317 -} // End namespace osdev  
318 -  
319 -#endif // OSDEV_COMPONENTS_MQTT_SYNCHRONIZEDQUEUE_H  
src/timemeasurement.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_MEASUREMENT_TIMEMEASUREMENT_H  
23 -#define OSDEV_COMPONENTS_MQTT_MEASUREMENT_TIMEMEASUREMENT_H  
24 -  
25 -#include <chrono>  
26 -#include <functional>  
27 -#include <ostream>  
28 -#include <string>  
29 -  
30 -namespace osdev {  
31 -namespace components {  
32 -namespace mqtt {  
33 -namespace measurement {  
34 -  
35 -using TimeMeasurementCallback = std::function<void(const std::string& id, std::chrono::steady_clock::time_point start, std::chrono::microseconds sinceStart, std::chrono::microseconds sinceLast)>;  
36 -  
37 -class TimeMeasurement  
38 -{  
39 -public:  
40 - TimeMeasurement(const std::string& id, const TimeMeasurementCallback& callback, bool measureOnDestruction = true);  
41 - ~TimeMeasurement();  
42 -  
43 - TimeMeasurement(const TimeMeasurement&) = delete;  
44 - TimeMeasurement& operator=(const TimeMeasurement&) = delete;  
45 - TimeMeasurement(TimeMeasurement&&) = default;  
46 - TimeMeasurement& operator=(TimeMeasurement&&) = default;  
47 -  
48 - void set();  
49 - void measure();  
50 -  
51 -private:  
52 - std::string m_id;  
53 -  
54 - std::chrono::steady_clock::time_point m_start;  
55 - std::chrono::steady_clock::time_point m_last;  
56 - TimeMeasurementCallback m_callback;  
57 - bool m_measureOnDestruction;  
58 -};  
59 -  
60 -template <typename Rep, typename Dur>  
61 -std::ostream& operator<<(std::ostream& os, const std::chrono::duration<Rep, Dur>& rhs)  
62 -{  
63 - os << rhs.count();  
64 - return os;  
65 -}  
66 -  
67 -} // End namespace measurement  
68 -} // End namespace mqtt  
69 -} // End namespace components  
70 -} // End namespace osdev  
71 -  
72 -#endif // OSDEV_COMPONENTS_MQTT_MEASUREMENT_TIMEMEASUREMENT_H  
src/token.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_TOKEN_H  
23 -#define OSDEV_COMPONENTS_MQTT_TOKEN_H  
24 -  
25 -// std  
26 -#include <ostream>  
27 -#include <string>  
28 -  
29 -// paho  
30 -#include <MQTTAsync.h>  
31 -  
32 -namespace osdev {  
33 -namespace components {  
34 -namespace mqtt {  
35 -  
36 -/*!  
37 - * \brief The Token class defines an operation token  
38 - */  
39 -class Token  
40 -{  
41 -public:  
42 - /*! @brief Construct an invalid token.  
43 - * The token number is -1 in that case. The client is undefined, in this case empty.  
44 - */  
45 - Token();  
46 -  
47 - /*! @brief Constructs token for an operation originating from specific client wrapper.  
48 - * @param clientId - Identifies the client wrapper  
49 - * @param tokenNr - Identifies the operation done on that client.  
50 - */  
51 - Token( const std::string &clientId, std::int32_t tokenNr );  
52 -  
53 - /*! @return True when token has a valid token number, false otherwise. */  
54 - bool isValid() const { return -1 == m_token; }  
55 -  
56 - /*! @return The operation token */  
57 - const std::string& clientId() const { return m_clientId; }  
58 -  
59 - /*! @return The operation token */  
60 - std::int32_t token() const { return m_token; }  
61 -  
62 - /*! @return True if Tokens have the same clientId and token number, false otherwise. */  
63 - bool equals( const Token &rhs ) const;  
64 -  
65 - /*!  
66 - * @brief Token is ordered.  
67 - * First on lexical test of clientId and with same clientId on token number.  
68 - */  
69 - bool smallerThan( const Token &rhs ) const;  
70 -  
71 -private:  
72 - std::string m_clientId; ///< Identified the client  
73 - std::int32_t m_token; ///< Identifies the operation on that client.  
74 -};  
75 -  
76 -/**  
77 - * @return True if Tokens have the same clientId and token number, false otherwise.  
78 - */  
79 -inline bool operator==( const Token &lhs, const Token &rhs )  
80 -{  
81 - return lhs.equals( rhs );  
82 -}  
83 -  
84 -inline bool operator==( const Token &lhs, std::int32_t rhs )  
85 -{  
86 - return lhs.token() == rhs;  
87 -}  
88 -  
89 -inline bool operator==( std::int32_t lhs, const Token &rhs )  
90 -{  
91 - return lhs == rhs;  
92 -}  
93 -  
94 -template <typename TLeft, typename TRight>  
95 -inline bool operator!=( const TLeft &lhs, const TRight &rhs )  
96 -{  
97 - return !( lhs == rhs );  
98 -}  
99 -  
100 -/*!  
101 - * @return True if Token lhs is smaller than token rhs  
102 - */  
103 -inline bool operator<( const Token &lhs, std::int32_t rhs )  
104 -{  
105 - return lhs.token() < rhs;  
106 -}  
107 -  
108 -inline bool operator<( std::int32_t lhs, const Token &rhs )  
109 -{  
110 - return lhs < rhs.token();  
111 -}  
112 -  
113 -inline bool operator<( const Token &lhs, const Token &rhs )  
114 -{  
115 - return lhs.smallerThan( rhs );  
116 -}  
117 -  
118 -/*!  
119 - * @brief Stream operator for a Token  
120 - */  
121 -std::ostream& operator<<( std::ostream &os, const Token &rhs );  
122 -  
123 -} // End namespace mqtt  
124 -} // End namespace components  
125 -} // End namespace osdev  
126 -  
127 -#endif // OSDEV_COMPONENTS_MQTT_TOKEN_H  
src/uriparser.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_URIPARSER_H  
23 -#define OSDEV_COMPONENTS_MQTT_URIPARSER_H  
24 -  
25 -// std  
26 -#include <string>  
27 -  
28 -#include "commondefs.h"  
29 -  
30 -namespace osdev {  
31 -namespace components {  
32 -namespace mqtt {  
33 -  
34 -/**  
35 - * @brief Helper class to parse, normalize, and replace the port service name by portnumber in a uri.  
36 - * example:  
37 - * opc.tcp://user:secret\@processmodel:processmodel/path1/path2?query3=value4#fragment5  
38 - * will result in  
39 - * opc.tcp://user:secret\@processmodel:12345/path1/path2?query3=value4#fragment5  
40 - * @note This assumes that the port service name was registered in the etc/services file under protocol tcp.  
41 - * Lookup of a portnumber for protocols other than tcp are not supported.  
42 - *  
43 - * IPv6 addresses in a uri are only parsable when they are wrapped in brackets ([]) (RFC 3986, section 3.2.2)  
44 - *  
45 - * @note This class is designed to handle a subset of all possible uris. The scheme and the authority part are  
46 - * expected not to be empty. The authority part can contain user and password information.  
47 - *  
48 - * @note Only scheme, hostname and port are converted to lowercase (see RFC 3986 6.2.2.1. Case Normalization)  
49 - *  
50 - * @note Special characters are escaped with percent encoding. This applies to user, password, path, query and fragment parts.  
51 - * The path and query part is escaped on a per element basis. This means that ParsedUri contains the raw query and path strings.  
52 - * The decoding is done when the methods parseQuery and parsePath are called.  
53 - */  
54 -class UriParser  
55 -{  
56 -public:  
57 - /**  
58 - * @brief Parses the specified uri string.  
59 - * @param uri The uri string to parse.  
60 - * @return A map containing the parsed uri.  
61 - * @note The path and query parts can still contain percent encoded special characters.  
62 - */  
63 - static ParsedUri parse(const std::string& uri);  
64 -  
65 - /**  
66 - * @brief Parse the query part of a parsed uri. Percent encoded special characters are decoded.  
67 - * @param parsedUri A ParsedUri object.  
68 - * @return key/value map.  
69 - */  
70 - static ParsedQuery parseQuery(const ParsedUri& parsedUri);  
71 -  
72 - /**  
73 - * @brief Parse the path part of a parsed uri. Percent encoded special characters are decoded.  
74 - * @param parsedUri A ParsedUri object.  
75 - * @return vector of path elements.  
76 - */  
77 - static ParsedPath parsePath(const ParsedUri& parsedUri);  
78 -  
79 - /**  
80 - * @brief Parses, normalizes, and replaces the port service name by portnumber in the specified uri string.  
81 - * @param uri The uri string to parse and normalize.  
82 - * @return The normalized uri string, with the port service name replaced by the portnumber.  
83 - */  
84 - static std::string normalize(const std::string& uri);  
85 -  
86 - /**  
87 - * @brief Converts a parsed uri back to a string.  
88 - * @param parsedUri The parsed uri to convert to string.  
89 - * @return The uri as string.  
90 - */  
91 - static std::string toString(const ParsedUri& parsedUri);  
92 -  
93 - /**  
94 - * @brief Get portnumber associated with a service.  
95 - * @param serviceName Name of the service for which a portnumber is searched.  
96 - * @param protocolName Name of the protocol for which the portname was registered.  
97 - * @return portnumber.  
98 - * @throws InvalidArgumentException when service is unknown.  
99 - * @throws SystemException when underlying systemcall fails.  
100 - */  
101 - static int getPortnumber(const std::string& serviceName, const std::string& protocolName = "tcp");  
102 -};  
103 -  
104 -} // End namespace mqtt  
105 -} // End namespace components  
106 -} // End namespace osdev  
107 -  
108 -#endif // OSDEV_COMPONENTS_MQTT_URIPARSER_H  
src/uriutils.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_URIUTILS_H  
23 -#define OSDEV_COMPONENTS_MQTT_URIUTILS_H  
24 -  
25 -// std  
26 -#include <string>  
27 -  
28 -#include "compiletimedigits.h"  
29 -  
30 -namespace osdev {  
31 -namespace components {  
32 -namespace mqtt {  
33 -  
34 -/**  
35 - * @brief Get the percent encoded string for a given character.  
36 - * @tparam N The character to encode.  
37 - * @return pointer to the encoded character string.  
38 - */  
39 -template <unsigned N>  
40 -inline const char* percentEncode()  
41 -{  
42 - static const auto* s_code =  
43 - (compiletime_string<'%'>{} + typename apply_bounded_range< //  
44 - 0, //  
45 - numberOfDigits<16>(N), //  
46 - string_builder< //  
47 - adapt_for_string_builder< //  
48 - ProduceDigits<N, 16>>>::template produce>::result{})  
49 - .chars;  
50 - return s_code;  
51 -}  
52 -  
53 -} // End namespace mqtt  
54 -} // End namespace components  
55 -} // End namespace osdev  
56 -  
57 -#endif // OSDEV_COMPONENTS_MQTT_URIUTILS_H  
src/utils.h deleted
1 -/* ****************************************************************************  
2 - * Copyright 2019 Open Systems Development BV *  
3 - * *  
4 - * Permission is hereby granted, free of charge, to any person obtaining a *  
5 - * copy of this software and associated documentation files (the "Software"), *  
6 - * to deal in the Software without restriction, including without limitation *  
7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, *  
8 - * and/or sell copies of the Software, and to permit persons to whom the *  
9 - * Software is furnished to do so, subject to the following conditions: *  
10 - * *  
11 - * The above copyright notice and this permission notice shall be included in *  
12 - * all copies or substantial portions of the Software. *  
13 - * *  
14 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *  
15 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  
16 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *  
17 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *  
18 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *  
19 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *  
20 - * DEALINGS IN THE SOFTWARE. *  
21 - * ***************************************************************************/  
22 -#ifndef OSDEV_COMPONENTS_MQTT_UTILS_H  
23 -#define OSDEV_COMPONENTS_MQTT_UTILS_H  
24 -  
25 -// std  
26 -#include <algorithm>  
27 -#include <functional>  
28 -#include <memory>  
29 -#include <vector>  
30 -  
31 -namespace osdev {  
32 -namespace components {  
33 -namespace mqtt {  
34 -  
35 -/**  
36 - * @brief Does nothing.  
37 - * Utility template function to explicitly use parameters, that would otherwise be unused.  
38 - * This helps to prevent the -Wunused-parameter warning.  
39 - */  
40 -template <typename... Args>  
41 -void apply_unused_parameters(const Args&...)  
42 -{  
43 -}  
44 -  
45 -/**  
46 - * @brief Converts (dynamic_cast) a std::unique_ptr from TFrom to TTo.  
47 - * @param from The std::unique_ptr to convert from TFrom to TTo.  
48 - * @return The converted std::unique_ptr.  
49 - */  
50 -template <typename TTo, typename TFrom>  
51 -std::unique_ptr<TTo> dynamic_unique_ptr_cast(std::unique_ptr<TFrom>&& from)  
52 -{  
53 - auto to = dynamic_cast<TTo*>(from.get());  
54 - if (nullptr == to) {  
55 - return std::unique_ptr<TTo>(nullptr);  
56 - }  
57 -  
58 - from.release();  
59 - return std::unique_ptr<TTo>(to);  
60 -}  
61 -  
62 -/**  
63 - * @brief Converts (dynamic_cast) a std::unique_ptr from TFrom to TTo.  
64 - * @param from The std::unique_ptr to convert from TFrom to TTo.  
65 - * @return The converted std::unique_ptr.  
66 - */  
67 -template <typename TTo, typename TFrom, typename TDeleter>  
68 -std::unique_ptr<TTo, TDeleter> dynamic_unique_ptr_cast(std::unique_ptr<TFrom, TDeleter>&& from)  
69 -{  
70 - auto to = dynamic_cast<TTo*>(from.get());  
71 - if (nullptr == to) {  
72 - return std::unique_ptr<TTo, TDeleter>(nullptr, from.get_deleter());  
73 - }  
74 -  
75 - from.release();  
76 - return std::unique_ptr<TTo, TDeleter>(to, std::move(from.get_deleter()));  
77 -}  
78 -  
79 -/**  
80 - * @brief Helper class for iteration of keys of a map.  
81 - */  
82 -template <typename TMap>  
83 -class KeyIterator : public TMap::iterator  
84 -{  
85 -public:  
86 - typedef typename TMap::iterator MapIterator;  
87 - typedef typename MapIterator::value_type::first_type KeyType;  
88 -  
89 - KeyIterator(const MapIterator& other)  
90 - : TMap::iterator(other)  
91 - {  
92 - }  
93 -  
94 - KeyType& operator*()  
95 - {  
96 - return TMap::iterator::operator*().first;  
97 - }  
98 -};  
99 -  
100 -/**  
101 - * @brief Helper function to get the begin KeyIterator from a map.  
102 - */  
103 -template <typename MapType>  
104 -KeyIterator<MapType> KeyBegin(MapType& map)  
105 -{  
106 - return KeyIterator<MapType>(map.begin());  
107 -}  
108 -  
109 -/**  
110 - * @brief Helper function to get the end KeyIterator from a map.  
111 - */  
112 -template <typename MapType>  
113 -KeyIterator<MapType> KeyEnd(MapType& map)  
114 -{  
115 - return KeyIterator<MapType>(map.end());  
116 -}  
117 -  
118 -/**  
119 - * @brief Helper class for iteration of keys of a const map.  
120 - */  
121 -template <typename TMap>  
122 -class KeyConstIterator : public TMap::const_iterator  
123 -{  
124 - typedef typename TMap::const_iterator TMapIterator;  
125 - typedef typename TMapIterator::value_type::first_type TKeyType;  
126 -  
127 -public:  
128 - KeyConstIterator(const TMapIterator& other)  
129 - : TMapIterator(other)  
130 - {  
131 - }  
132 -  
133 - const TKeyType& operator*()  
134 - {  
135 - return TMapIterator::operator*().first;  
136 - }  
137 -};  
138 -  
139 -/**  
140 - * @brief Helper function to get the cbegin KeyConstIterator from a const map.  
141 - */  
142 -template <typename TMap>  
143 -KeyConstIterator<TMap> KeyBegin(const TMap& map)  
144 -{  
145 - return KeyConstIterator<TMap>(map.cbegin());  
146 -}  
147 -  
148 -/**  
149 - * @brief Helper function to get the cend KeyConstIterator from a const map.  
150 - */  
151 -template <typename TMap>  
152 -KeyConstIterator<TMap> KeyEnd(const TMap& map)  
153 -{  
154 - return KeyConstIterator<TMap>(map.cend());  
155 -}  
156 -  
157 -/**  
158 - * @brief Helper function to get the difference of the keys in two maps.  
159 - * @param map1 The first map for which to examine the keys.  
160 - * @param map2 The second map for which to examine the keys.  
161 - * @return Collection of keys present in map1, but not in map2.  
162 - * @note The types of the keys in the maps must be identical.  
163 - */  
164 -template <typename TMap1, typename TMap2>  
165 -std::vector<typename TMap1::key_type> keyDifference(  
166 - const TMap1& map1,  
167 - const TMap2& map2,  
168 - const std::function<bool(const typename TMap1::key_type& key1, const typename TMap1::key_type& key2)>& keyCompare = std::less<typename TMap1::key_type>())  
169 -{  
170 - static_assert(std::is_same<  
171 - typename TMap1::key_type,  
172 - typename TMap2::key_type>::value,  
173 - "Inconsistent key types.");  
174 -  
175 - typedef typename TMap1::key_type Key;  
176 - std::vector<Key> onlyInMap1;  
177 - std::set_difference(  
178 - KeyBegin(map1),  
179 - KeyEnd(map1),  
180 - KeyBegin(map2),  
181 - KeyEnd(map2),  
182 - std::inserter(onlyInMap1, onlyInMap1.begin()),  
183 - keyCompare);  
184 - return onlyInMap1;  
185 -}  
186 -  
187 -/**  
188 - * @brief Helper function to get the intersection of the keys in two maps.  
189 - * @param map1 The first map for which to examine the keys.  
190 - * @param map2 The second map for which to examine the keys.  
191 - * @return Collection of keys present in both maps.  
192 - * @note The types of the keys in the maps must be identical.  
193 - */  
194 -template <typename TMap1, typename TMap2>  
195 -std::vector<typename TMap1::key_type> keyIntersection(  
196 - const TMap1& map1,  
197 - const TMap2& map2,  
198 - const std::function<bool(const typename TMap1::key_type& key1, const typename TMap1::key_type& key2)>& keyCompare = std::less<typename TMap1::key_type>())  
199 -{  
200 - static_assert(std::is_same<  
201 - typename TMap1::key_type,  
202 - typename TMap2::key_type>::value,  
203 - "Inconsistent key types.");  
204 -  
205 - typedef typename TMap1::key_type Key;  
206 - std::vector<Key> inBothMaps;  
207 - std::set_intersection(  
208 - KeyBegin(map1),  
209 - KeyEnd(map1),  
210 - KeyBegin(map2),  
211 - KeyEnd(map2),  
212 - std::inserter(inBothMaps, inBothMaps.begin()),  
213 - keyCompare);  
214 - return inBothMaps;  
215 -}  
216 -  
217 -/**  
218 - * @brief Determine the absolute path of the binary that belongs to a process.  
219 - * @param pid Process Id ifor which to determine the path to the binary. If pid equals -1 then the pid of the current process is used.  
220 - * @return Absolute path to the binary.  
221 - * @throw SystemException if call to readlink fails.  
222 - * @throw PathException if path is to long.  
223 - * @note Works only for processes owned by the user that is calling this function.  
224 - */  
225 -std::string getPathToBinary(int pid = -1);  
226 -  
227 -} // End namespace mqtt  
228 -} // End namespace components  
229 -} // End namespace osdev  
230 -  
231 -#endif // OSDEV_COMPONENTS_MQTT_UTILS_H