Commit 427cbf544a42561d8d10bf48933d7218bf095c4d

Authored by Peter M. Groen
1 parent c6c62b01

Preparation Subclassing Subscriber

examples/pub/CMakeLists.txt
... ... @@ -5,7 +5,7 @@ include(projectheader)
5 5 project_header(test_mqtt_pub)
6 6  
7 7 include_directories( SYSTEM
8   - ${CMAKE_CURRENT_SOURCE_DIR}/../../src
  8 + ${CMAKE_CURRENT_SOURCE_DIR}/../../include
9 9 )
10 10  
11 11 include(compiler)
... ... @@ -21,7 +21,7 @@ add_executable( ${PROJECT_NAME}
21 21  
22 22 target_link_libraries(
23 23 ${PROJECT_NAME}
24   - mqtt
  24 + mqtt-cpp
25 25 )
26 26  
27 27 set_target_properties( ${PROJECT_NAME} PROPERTIES
... ...
examples/pub/main.cpp
... ... @@ -78,7 +78,7 @@ int main( int argc, char* argv[] )
78 78 {
79 79 std::cout << "{OK}" << std::endl;
80 80 std::cout << "Connecting to the broker : ";
81   - pPublisher->connect( "localhost", 1883, "", "" );
  81 + pPublisher->connect( "office.osdev.nl", 1883, "", "" );
82 82  
83 83 // Assume we are connected now, start publishing.
84 84 while( 1 )
... ... @@ -86,7 +86,7 @@ int main( int argc, char* argv[] )
86 86 std::string payload = "<Timestamp value=\"" + std::to_string( getEpochUSecs() ) + "\" /><MessageNumber value=\"" + std::to_string( messageNumber ) + "\" />" ;
87 87 pPublisher->publish( std::string( "test/publisher/TestPublisher" ), payload );
88 88  
89   - sleepcp( 1, T_SECONDS );
  89 + sleepcp( 1, T_MICRO );
90 90 if( messageNumber > 2000000000 )
91 91 messageNumber = -1;
92 92  
... ...
examples/pub/publisher.cpp
... ... @@ -21,7 +21,7 @@
21 21 * ***************************************************************************/
22 22  
23 23 // osdev::components::mqtt
24   -#include "token.h"
  24 +// #include "token.h"
25 25  
26 26 // mqtt_tests
27 27 #include "publisher.h"
... ...
examples/sub/CMakeLists.txt
... ... @@ -5,7 +5,7 @@ include(projectheader)
5 5 project_header(test_mqtt_sub)
6 6  
7 7 include_directories( SYSTEM
8   - ${CMAKE_CURRENT_SOURCE_DIR}/../../src
  8 + ${CMAKE_CURRENT_SOURCE_DIR}/../../include
9 9 )
10 10  
11 11 include(compiler)
... ... @@ -21,7 +21,7 @@ add_executable( ${PROJECT_NAME}
21 21  
22 22 target_link_libraries(
23 23 ${PROJECT_NAME}
24   - mqtt
  24 + mqtt-cpp
25 25 )
26 26  
27 27 set_target_properties( ${PROJECT_NAME} PROPERTIES
... ...
examples/sub/main.cpp
... ... @@ -71,12 +71,12 @@ int main( int argc, char* argv[] )
71 71  
72 72 std::cout << "Creating the subscriber : ";
73 73 // Create the subscriber
74   - Subscriber *pSubscriber = new Subscriber();
  74 + Subscriber *pSubscriber = new Subscriber( "Test_Subscriber" );
75 75 if( pSubscriber != nullptr )
76 76 {
77 77 std::cout << "[OK]" << std::endl;
78 78 std::cout << "Connecting to the test-broker : " << std::endl;
79   - pSubscriber->connect( "localhost", 1883, "", "" );
  79 + pSubscriber->connect( "office.osdev.nl", 1883, "", "" );
80 80 std::cout << "Subscribing to the test-topic....." << std::endl;
81 81 pSubscriber->subscribe( "test/publisher/TestPublisher" );
82 82  
... ...
examples/sub/subscriber.cpp
... ... @@ -20,27 +20,13 @@
20 20 * DEALINGS IN THE SOFTWARE. *
21 21 * ***************************************************************************/
22 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 32 void Subscriber::receive_data( const std::string &message_topic, const std::string &message_payload )
... ...
examples/sub/subscriber.h
... ... @@ -22,27 +22,19 @@
22 22 #pragma once
23 23  
24 24 // std
25   -#include <memory>
26 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 32 public:
35   - Subscriber();
  33 + Subscriber( const std::string &client_id );
36 34  
37 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 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 23 # ==============================================================================
24 24 include(projectheader)
25 25  
26   -project_header(mqtt)
  26 +project_header(mqtt-cpp)
27 27  
28 28 find_package( Boost REQUIRED COMPONENTS regex )
29 29  
30 30 include(compiler)
31 31  
32 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 36 set(SRC_LIST
... ... @@ -40,8 +39,6 @@ set(SRC_LIST
40 39 ${CMAKE_CURRENT_SOURCE_DIR}/clientpaho.cpp
41 40 ${CMAKE_CURRENT_SOURCE_DIR}/commondefs.cpp
42 41 ${CMAKE_CURRENT_SOURCE_DIR}/connectionstatus.cpp
43   - ${CMAKE_CURRENT_SOURCE_DIR}/compiletimedigits.h
44   - ${CMAKE_CURRENT_SOURCE_DIR}/compiletimestring.h
45 42 ${CMAKE_CURRENT_SOURCE_DIR}/credentials.cpp
46 43 ${CMAKE_CURRENT_SOURCE_DIR}/errorcode.cpp
47 44 ${CMAKE_CURRENT_SOURCE_DIR}/token.cpp
... ... @@ -63,23 +60,23 @@ set(SRC_LIST
63 60 ${CMAKE_CURRENT_SOURCE_DIR}/stringutils.cpp
64 61 ${CMAKE_CURRENT_SOURCE_DIR}/uriparser.cpp
65 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 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
Changes suppressed. Click to show
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