sdbus++: support special double values

Enable properties to have default values of special IEEE floating
points: 'NaN', 'infinity' and 'epsilon'.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I7c2daa3c36cde69c2ee06afd75a8d2e77992c6e7
diff --git a/docs/interface.md b/docs/interface.md
index 5137a92..635bfb6 100644
--- a/docs/interface.md
+++ b/docs/interface.md
@@ -85,6 +85,18 @@
 * object_path
 * signature
 
+### Special type values
+
+For 'double' types it is possible to express one of the special values:
+    * 'NaN' (case-insensitive)
+        - A quiet-type not-a-number value.
+    * 'Infinity' (case-insensitive)
+        - A positive infinity value.
+    * '-Infinity' (case-insensitive)
+        - A negative infinity value.
+    * 'Epsilon' (case-insensitive)
+        - An epsilon value.
+
 ### Containers
 Container types can also be expressed, but the contained-type should be
 expressed within square-brackets `[]`.  The following containers are supported:
diff --git a/test/server/Test.interface.yaml b/test/server/Test.interface.yaml
index 30df1f9..ed98eb3 100644
--- a/test/server/Test.interface.yaml
+++ b/test/server/Test.interface.yaml
@@ -22,3 +22,15 @@
       type: uint64
     - name: ObjectPath
       type: object_path
+    - name: DoubleAsNAN
+      type: double
+      default: NaN
+    - name: DoubleAsInf
+      type: double
+      default: Infinity
+    - name: DoubleAsNegInf
+      type: double
+      default: -Infinity
+    - name: DoubleAsEpsilon
+      type: double
+      default: Epsilon
diff --git a/test/server/object.cpp b/test/server/object.cpp
index 8faa668..76e077d 100644
--- a/test/server/object.cpp
+++ b/test/server/object.cpp
@@ -103,3 +103,24 @@
                 sd_bus_emit_interfaces_removed_strv(_, StrEq(objPath), _))
         .Times(0);
 }
+
+TEST_F(Object, DoubleHasDefaultValues)
+{
+    // Simulate the typical usage of a service
+    sdbusplus::server::manager::manager objManager(bus, objPath);
+    bus.request_name(busName);
+
+    EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(_, StrEq(objPath)))
+        .Times(1);
+    EXPECT_CALL(sdbusMock,
+                sd_bus_emit_interfaces_added_strv(_, StrEq(objPath), _))
+        .Times(0);
+
+    auto test = std::make_unique<TestInherit>(bus, objPath);
+    EXPECT_TRUE(std::isnan(test->doubleAsNAN()));
+    EXPECT_TRUE(std::isinf(test->doubleAsInf()) &&
+                !std::signbit(test->doubleAsInf()));
+    EXPECT_TRUE(std::isinf(test->doubleAsNegInf()) &&
+                std::signbit(test->doubleAsNegInf()));
+    EXPECT_EQ(std::numeric_limits<double>::epsilon(), test->doubleAsEpsilon());
+}
diff --git a/tools/sdbusplus/property.py b/tools/sdbusplus/property.py
index 6eb952e..490fabf 100644
--- a/tools/sdbusplus/property.py
+++ b/tools/sdbusplus/property.py
@@ -25,6 +25,20 @@
                  self.typeName.lower() == "string"):
                 # Wrap string type default values with double-quotes
                 self.defaultValue = "\"" + self.defaultValue + "\""
+            elif(isinstance(self.defaultValue, str) and
+                    self.typeName.lower() == "double"):
+                if self.defaultValue.lower() == "nan":
+                    self.defaultValue = \
+                        'std::numeric_limits<double>::quiet_NaN()'
+                elif self.defaultValue.lower() == "infinity":
+                    self.defaultValue = \
+                        'std::numeric_limits<double>::infinity()'
+                elif self.defaultValue.lower() == "-infinity":
+                    self.defaultValue = \
+                        '-std::numeric_limits<double>::infinity()'
+                elif self.defaultValue.lower() == "epsilon":
+                    self.defaultValue = \
+                        'std::numeric_limits<double>::epsilon()'
 
         super(Property, self).__init__(**kwargs)
 
diff --git a/tools/sdbusplus/templates/interface.server.hpp.mako b/tools/sdbusplus/templates/interface.server.hpp.mako
index 90c8418..389b872 100644
--- a/tools/sdbusplus/templates/interface.server.hpp.mako
+++ b/tools/sdbusplus/templates/interface.server.hpp.mako
@@ -1,4 +1,5 @@
 #pragma once
+#include <limits>
 #include <map>
 #include <sdbusplus/sdbus.hpp>
 #include <sdbusplus/server.hpp>