codemaker/source/cppumaker/cpputype.cxx |  159 ++++++++++++++++++++++++++++++++
 cppu/qa/cppumaker/test_cppumaker.cxx    |   32 ++++++
 cppu/qa/cppumaker/types.idl             |   54 ++++++++++
 3 files changed, 245 insertions(+)

New commits:
commit e1c6f36d8bcc0799281e3a7e244175f682d97cb2
Author:     Tor Lillqvist <t...@collabora.com>
AuthorDate: Thu Mar 16 15:32:10 2023 +0200
Commit:     Tor Lillqvist <t...@collabora.com>
CommitDate: Fri Mar 17 11:46:36 2023 +0000

    Add a to_string() function to the code generated for UNO IDL constant groups
    
    If the inpt matches one of the constants exactly, the result is the
    name of that constant. If the input matches some combination of
    constant values that are single bits, the result is the sequence of
    the names of those constants joined with plus signs.
    
    For instance, if the IDL has:
    
    constants Constants {
        const byte BIT0 = 1;
        const byte BIT1 = 2;
        const byte BIT2 = 4;
        const byte BIT3 = 8;
    }
    
    The result of Constants::to_string(5) is "BIT0+BIT2", and the result
    of Constants::to_string(17) is "17".
    
    I am sure there are corner cases that aren't handled as would be
    intuitive, especially with types that include unsigned values.
    Correspondingly, the semantics of the generated to_string() functions
    is not formally defined.
    
    Also add a unit test for the new functionality.
    
    Change-Id: I14aa826d0989ac6dfe97dd5c09119b1601c65643
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148995
    Tested-by: Jenkins
    Reviewed-by: Tor Lillqvist <t...@collabora.com>

diff --git a/codemaker/source/cppumaker/cpputype.cxx 
b/codemaker/source/cppumaker/cpputype.cxx
index bb8e3ed7d33c..c4ccbbb7ad0c 100644
--- a/codemaker/source/cppumaker/cpputype.cxx
+++ b/codemaker/source/cppumaker/cpputype.cxx
@@ -21,6 +21,7 @@
 #include <sal/log.hxx>
 
 #include <algorithm>
+#include <bitset>
 #include <cassert>
 #include <cstdlib>
 #include <map>
@@ -1660,6 +1661,7 @@ void ConstantGroup::dumpHdlFile(
     OUString headerDefine(dumpHeaderDefine(out, u"HDL"));
     out << "\n";
     addDefaultHIncludes(includes);
+    includes.addRtlUstringHxx();
     includes.dump(out, nullptr, true);
     out << "\n";
     if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, true)) {
@@ -1685,6 +1687,10 @@ void ConstantGroup::dumpHppFile(
 
 void ConstantGroup::dumpDeclaration(FileStream & out)
 {
+    unoidl::ConstantValue::Type largestType = 
unoidl::ConstantValue::TYPE_BOOLEAN;
+    OUString largestTypeName = "sal_Bool";
+    bool haveFloatingPoint = false;
+
     for (const unoidl::ConstantGroupEntity::Member& member : 
entity_->getMembers()) {
         out << "static const ";
         switch (member.value.type) {
@@ -1693,30 +1699,60 @@ void ConstantGroup::dumpDeclaration(FileStream & out)
             break;
         case unoidl::ConstantValue::TYPE_BYTE:
             out << "::sal_Int8";
+            if (largestType < unoidl::ConstantValue::TYPE_BYTE) {
+                largestType = unoidl::ConstantValue::TYPE_BYTE;
+                largestTypeName = "sal_Int8";
+            }
             break;
         case unoidl::ConstantValue::TYPE_SHORT:
             out << "::sal_Int16";
+            if (largestType < unoidl::ConstantValue::TYPE_SHORT) {
+                largestType = unoidl::ConstantValue::TYPE_SHORT;
+                largestTypeName = "sal_Int16";
+            }
             break;
         case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
             out << "::sal_uInt16";
+            if (largestType < unoidl::ConstantValue::TYPE_UNSIGNED_SHORT) {
+                largestType = unoidl::ConstantValue::TYPE_UNSIGNED_SHORT;
+                largestTypeName = "sal_uInt16";
+            }
             break;
         case unoidl::ConstantValue::TYPE_LONG:
             out << "::sal_Int32";
+            if (largestType < unoidl::ConstantValue::TYPE_LONG) {
+                largestType = unoidl::ConstantValue::TYPE_LONG;
+                largestTypeName = "sal_Int32";
+            }
             break;
         case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
             out << "::sal_uInt32";
+            if (largestType < unoidl::ConstantValue::TYPE_UNSIGNED_LONG) {
+                largestType = unoidl::ConstantValue::TYPE_UNSIGNED_LONG;
+                largestTypeName = "sal_uInt32";
+            }
             break;
         case unoidl::ConstantValue::TYPE_HYPER:
             out << "::sal_Int64";
+            if (largestType < unoidl::ConstantValue::TYPE_HYPER) {
+                largestType = unoidl::ConstantValue::TYPE_HYPER;
+                largestTypeName = "sal_Int64";
+            }
             break;
         case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
             out << "::sal_uInt64";
+            if (largestType < unoidl::ConstantValue::TYPE_UNSIGNED_HYPER) {
+                largestType = unoidl::ConstantValue::TYPE_UNSIGNED_HYPER;
+                largestTypeName = "sal_uInt64";
+            }
             break;
         case unoidl::ConstantValue::TYPE_FLOAT:
             out << "float";
+            haveFloatingPoint = true;
             break;
         case unoidl::ConstantValue::TYPE_DOUBLE:
             out << "double";
+            haveFloatingPoint = true;
             break;
         }
         out << " " << member.name << " = ";
@@ -1770,6 +1806,129 @@ void ConstantGroup::dumpDeclaration(FileStream & out)
         }
         out << ";\n";
     }
+
+    // If there are only integral constants, generate a function to
+    // produce a symbolic string of a value of the type.
+
+    if (!haveFloatingPoint) {
+        out << "\n"
+              "#ifdef LIBO_INTERNAL_ONLY\n";
+        out << "inline ::rtl::OUString to_string(::" << largestTypeName << " 
input_value) {\n";
+
+        out << "    switch (input_value) {\n";
+
+        std::set<sal_uInt64> handledValues;
+
+        // Go through each constant and generate a case for exactly
+        // that, unless there was another constant with the same
+        // value.
+        for (const unoidl::ConstantGroupEntity::Member& member : 
entity_->getMembers()) {
+            bool skip = false;
+            switch (member.value.type) {
+            case unoidl::ConstantValue::TYPE_BOOLEAN:
+                if 
(!handledValues.insert(static_cast<sal_uInt64>(member.value.booleanValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_BYTE:
+                if 
(!handledValues.insert(static_cast<sal_uInt64>(member.value.byteValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_SHORT:
+                if 
(!handledValues.insert(static_cast<sal_uInt64>(member.value.shortValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
+                if 
(!handledValues.insert(static_cast<sal_uInt64>(member.value.unsignedShortValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_LONG:
+                if 
(!handledValues.insert(static_cast<sal_uInt64>(member.value.longValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
+                if 
(!handledValues.insert(static_cast<sal_uInt64>(member.value.unsignedLongValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_HYPER:
+                if 
(!handledValues.insert(static_cast<sal_uInt64>(member.value.hyperValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
+                if 
(!handledValues.insert(member.value.unsignedHyperValue).second)
+                    skip = true;
+                break;
+            default:
+                assert(false); // Can not happen
+            }
+
+            if (!skip)
+                out << "    case (" << largestTypeName << ")" << member.name 
<< ": return \"" << member.name << "\";\n";
+        }
+        out << "    default:\n";
+
+        // Next generate code to check for each individual bit, for
+        // the constants that are single bit values.
+
+        handledValues.clear();
+
+        out << "        ::rtl::OUString result_string;\n"
+               "        " << largestTypeName << " accum_value = 
input_value;\n";
+        for (const unoidl::ConstantGroupEntity::Member& member : 
entity_->getMembers()) {
+            bool skip = false;
+            switch (member.value.type) {
+            case unoidl::ConstantValue::TYPE_BOOLEAN:
+                if (!member.value.booleanValue || 
!handledValues.insert(static_cast<sal_uInt64>(member.value.booleanValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_BYTE:
+                if (std::bitset<8>(member.value.byteValue).count() != 1 || 
!handledValues.insert(static_cast<sal_uInt64>(member.value.byteValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_SHORT:
+                if (std::bitset<16>(member.value.shortValue).count() != 1 || 
!handledValues.insert(static_cast<sal_uInt64>(member.value.shortValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
+                if (std::bitset<16>(member.value.unsignedShortValue).count() 
!= 1 || 
!handledValues.insert(static_cast<sal_uInt64>(member.value.unsignedShortValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_LONG:
+                if (std::bitset<32>(member.value.longValue).count() != 1 || 
!handledValues.insert(static_cast<sal_uInt64>(member.value.longValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
+                if (std::bitset<32>(member.value.unsignedLongValue).count() != 
1 || 
!handledValues.insert(static_cast<sal_uInt64>(member.value.unsignedLongValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_HYPER:
+                if (std::bitset<64>(member.value.hyperValue).count() != 1 || 
!handledValues.insert(static_cast<sal_uInt64>(member.value.hyperValue)).second)
+                    skip = true;
+                break;
+            case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
+                if (std::bitset<64>(member.value.unsignedHyperValue).count() 
!= 1 || !handledValues.insert(member.value.unsignedHyperValue).second)
+                    skip = true;
+                break;
+            default:
+                assert(false);
+            }
+
+            if (!skip)
+                out << "        if ((accum_value&" << member.name << ") == (" 
<< largestTypeName << ")" << member.name << ") {\n"
+                       "            if (!result_string.isEmpty())\n"
+                       "                result_string += \"+\";\n"
+                       "            result_string += \"" << member.name << 
"\";\n"
+                       "            accum_value &= ~" << member.name << ";\n"
+                       "        }\n";
+        }
+        out << "        if (accum_value == 0 && !result_string.isEmpty())\n"
+               "            return result_string;\n"
+               "    }\n";
+
+        out << "    return ::rtl::OUString::number(input_value);\n"
+               "}\n"
+               "#endif\n";
+        // The caller takes care of finally calling dumpNamespaceClose().
+    }
 }
 
 void dumpTypeParameterName(FileStream & out, std::u16string_view name)
diff --git a/cppu/qa/cppumaker/test_cppumaker.cxx 
b/cppu/qa/cppumaker/test_cppumaker.cxx
index a6d3e4942f06..cec02d3c710e 100644
--- a/cppu/qa/cppumaker/test_cppumaker.cxx
+++ b/cppu/qa/cppumaker/test_cppumaker.cxx
@@ -352,6 +352,9 @@
 #include <test/codemaker/cppumaker/TestException1.hpp>
 #include <test/codemaker/cppumaker/TestException2.hpp>
 #include <test/codemaker/cppumaker/Constants.hpp>
+#include <test/codemaker/cppumaker/ByteBits.hpp>
+#include <test/codemaker/cppumaker/ShortBits.hpp>
+#include <test/codemaker/cppumaker/UnsignedHyperBits.hpp>
 
 #include <memory>
 #include <com/sun/star/uno/Any.hxx>
@@ -390,11 +393,14 @@ public:
 
     void testConstants();
 
+    void testSymbolicConstants();
+
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testBigStruct);
     CPPUNIT_TEST(testPolyStruct);
     CPPUNIT_TEST(testExceptions);
     CPPUNIT_TEST(testConstants);
+    CPPUNIT_TEST(testSymbolicConstants);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -550,6 +556,32 @@ void Test::testConstants() {
         test::codemaker::cppumaker::Constants::unsignedHyperMax);
 }
 
+void Test::testSymbolicConstants() {
+    CPPUNIT_ASSERT_EQUAL(OUString("byteMin"), 
test::codemaker::cppumaker::Constants::to_string(static_cast<sal_uInt64>(-128)));
+    CPPUNIT_ASSERT_EQUAL(OUString("byteMax"), 
test::codemaker::cppumaker::Constants::to_string(127));
+    CPPUNIT_ASSERT_EQUAL(OUString("longMin"), 
test::codemaker::cppumaker::Constants::to_string(static_cast<sal_uInt64>(-2147483648)));
+    CPPUNIT_ASSERT_EQUAL(OUString("longMax"), 
test::codemaker::cppumaker::Constants::to_string(2147483647));
+    CPPUNIT_ASSERT_EQUAL(OUString("hyperMin"), 
test::codemaker::cppumaker::Constants::to_string(static_cast<sal_uInt64>(SAL_MIN_INT64)));
+    CPPUNIT_ASSERT_EQUAL(OUString("hyperMax"), 
test::codemaker::cppumaker::Constants::to_string(SAL_MAX_INT64));
+    CPPUNIT_ASSERT_EQUAL(OUString("17"), 
test::codemaker::cppumaker::Constants::to_string(17));
+    CPPUNIT_ASSERT_EQUAL(OUString("2147483646"), 
test::codemaker::cppumaker::Constants::to_string(2147483646));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("0"), 
test::codemaker::cppumaker::ByteBits::to_string(0));
+    CPPUNIT_ASSERT_EQUAL(OUString("BIT0+BIT2"), 
test::codemaker::cppumaker::ByteBits::to_string(5));
+    CPPUNIT_ASSERT_EQUAL(OUString("BIT4"), 
test::codemaker::cppumaker::ByteBits::to_string(16));
+    CPPUNIT_ASSERT_EQUAL(OUString("BIT0+BIT4"), 
test::codemaker::cppumaker::ByteBits::to_string(17));
+    CPPUNIT_ASSERT_EQUAL(OUString("BIT7"), 
test::codemaker::cppumaker::ByteBits::to_string(-128));
+    CPPUNIT_ASSERT_EQUAL(OUString("ALL"), 
test::codemaker::cppumaker::ByteBits::to_string(-1));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("BIT7"), 
test::codemaker::cppumaker::ShortBits::to_string(128));
+    CPPUNIT_ASSERT_EQUAL(OUString("ALL"), 
test::codemaker::cppumaker::ShortBits::to_string(-1));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("BIT63"), 
test::codemaker::cppumaker::UnsignedHyperBits::to_string(9223372036854775808u));
+    CPPUNIT_ASSERT_EQUAL(OUString("BIT0+BIT62"), 
test::codemaker::cppumaker::UnsignedHyperBits::to_string(4611686018427387905));
+    CPPUNIT_ASSERT_EQUAL(OUString("BIT0+BIT63"), 
test::codemaker::cppumaker::UnsignedHyperBits::to_string(9223372036854775809u));
+    CPPUNIT_ASSERT_EQUAL(OUString("ALL"), 
test::codemaker::cppumaker::UnsignedHyperBits::to_string(SAL_MAX_UINT64));
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
 
 }
diff --git a/cppu/qa/cppumaker/types.idl b/cppu/qa/cppumaker/types.idl
index b4dbe2e1de13..25bac18ff920 100644
--- a/cppu/qa/cppumaker/types.idl
+++ b/cppu/qa/cppumaker/types.idl
@@ -697,6 +697,60 @@ constants Constants {
     const unsigned hyper unsignedHyperMax = 18446744073709551615;
 };
 
+constants ByteBits {
+    const byte BIT0 = 1;
+    const byte BIT1 = 2;
+    const byte BIT2 = 4;
+    const byte BIT3 = 8;
+    const byte BIT4 = 16;
+    const byte BIT5 = 32;
+    const byte BIT6 = 64;
+    const byte BIT7 = -128;
+    const byte ALL = -1;
+};
+
+constants ShortBits {
+    const short BIT0 = 1;
+    const short BIT1 = 2;
+    const short BIT2 = 4;
+    const short BIT3 = 8;
+    const short BIT4 = 16;
+    const short BIT5 = 32;
+    const short BIT6 = 64;
+    const short BIT7 = 128;
+    const short BIT8 = 256;
+    const short BIT9 = 512;
+    const short BIT10 = 1024;
+    const short BIT11 = 2048;
+    const short BIT12 = 4096;
+    const short BIT13 = 8192;
+    const short BIT14 = 16384;
+    const short BIT15 = -32768;
+    const short ALL = -1;
+};
+
+constants UnsignedHyperBits {
+    const unsigned hyper BIT0 = 1;
+    const unsigned hyper BIT1 = 2;
+    const unsigned hyper BIT2 = 4;
+    const unsigned hyper BIT3 = 8;
+    const unsigned hyper BIT4 = 16;
+    const unsigned hyper BIT5 = 32;
+    const unsigned hyper BIT6 = 64;
+    const unsigned hyper BIT7 = 128;
+    const unsigned hyper BIT8 = 256;
+    const unsigned hyper BIT9 = 512;
+    const unsigned hyper BIT10 = 1024;
+    const unsigned hyper BIT11 = 2048;
+    const unsigned hyper BIT12 = 4096;
+    const unsigned hyper BIT13 = 8192;
+    const unsigned hyper BIT14 = 16384;
+    const unsigned hyper BIT15 = 32768;
+    const unsigned hyper BIT62 = 4611686018427387904;
+    const unsigned hyper BIT63 = 9223372036854775808;
+    const unsigned hyper ALL = 18446744073709551615;
+};
+
 }; }; };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to