Add a mathmatic unit conver tools to format numbers.
author石博文 <sbw@sbw.so>
Tue, 16 Jan 2018 05:01:37 +0000 (13:01 +0800)
committerzccrs <ccrr1314@live.com>
Tue, 16 Jan 2018 05:45:16 +0000 (13:45 +0800)
Change-Id: Ie01377598ec64efb64a3a7df7df7ac0615020ac4

12 files changed:
src/util/DAbstractUnitFormatter [new file with mode: 0644]
src/util/DDiskSizeFormatter [new file with mode: 0644]
src/util/DTimeUnitFormatter [new file with mode: 0644]
src/util/dabstractunitformatter.cpp [new file with mode: 0644]
src/util/dabstractunitformatter.h [new file with mode: 0644]
src/util/ddisksizeformatter.cpp [new file with mode: 0644]
src/util/ddisksizeformatter.h [new file with mode: 0644]
src/util/dtimeunitformatter.cpp [new file with mode: 0644]
src/util/dtimeunitformatter.h [new file with mode: 0644]
src/util/util.pri
tests/dutiltester.cpp
tests/dutiltester.h

diff --git a/src/util/DAbstractUnitFormatter b/src/util/DAbstractUnitFormatter
new file mode 100644 (file)
index 0000000..2d494ea
--- /dev/null
@@ -0,0 +1 @@
+#include "dabstractunitformatter.h"
diff --git a/src/util/DDiskSizeFormatter b/src/util/DDiskSizeFormatter
new file mode 100644 (file)
index 0000000..6584e09
--- /dev/null
@@ -0,0 +1 @@
+#include "ddisksizeformatter.h"
diff --git a/src/util/DTimeUnitFormatter b/src/util/DTimeUnitFormatter
new file mode 100644 (file)
index 0000000..07d52a6
--- /dev/null
@@ -0,0 +1 @@
+#include "dtimeunitformatter.h"
diff --git a/src/util/dabstractunitformatter.cpp b/src/util/dabstractunitformatter.cpp
new file mode 100644 (file)
index 0000000..418ed31
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dabstractunitformatter.h"
+
+DCORE_BEGIN_NAMESPACE
+
+DAbstractUnitFormatter::DAbstractUnitFormatter()
+{
+
+}
+
+DAbstractUnitFormatter::~DAbstractUnitFormatter()
+{
+
+}
+
+qreal DAbstractUnitFormatter::formatAs(qreal value, int currentUnit, const int targetUnit) const
+{
+    while (currentUnit < targetUnit)
+        value /= unitConvertRate(currentUnit++);
+    while (currentUnit > targetUnit)
+        value *= unitConvertRate(--currentUnit);
+
+    return value;
+}
+
+QPair<qreal, int> DAbstractUnitFormatter::format(const qreal value, const int unit) const
+{
+    // can convert to smaller unit
+    if (unit > unitMin() && value < unitValueMin(unit))
+        return format(value * unitConvertRate(unit - 1), unit - 1);
+
+    // can convert to bigger unit
+    if (unit < unitMax() && value > unitValueMax(unit))
+        return format(value / unitConvertRate(unit), unit + 1);
+
+    return QPair<qreal, int>(value, unit);
+}
+
+QList<QPair<qreal, int> > DAbstractUnitFormatter::formatAsUnitList(const qreal value, int unit) const
+{
+    if (qFuzzyIsNull(value))
+        return QList<QPair<qreal, int>>();
+
+    if (value < unitValueMin(unit) || unit == unitMin())
+    {
+        if (unit != unitMin())
+            return formatAsUnitList(value * unitConvertRate(unit - 1), unit - 1);
+        else
+            return std::move(QList<QPair<qreal, int>>() << QPair<qreal, int>(value, unit));
+    }
+
+    ulong _value = ulong(value);
+    QList<QPair<qreal, int>> ret = formatAsUnitList(value - _value, unit);
+
+    while (_value && unit != unitMax())
+    {
+        const ulong rate = unitConvertRate(unit);
+        const ulong r = _value % rate;
+        if (r)
+            ret.push_front(QPair<qreal, int>(r, unit));
+
+        unit += 1;
+        _value /= rate;
+    }
+
+    if (_value)
+        ret.push_front(QPair<qreal, int>(_value, unit));
+
+    return ret;
+}
+
+DCORE_END_NAMESPACE
diff --git a/src/util/dabstractunitformatter.h b/src/util/dabstractunitformatter.h
new file mode 100644 (file)
index 0000000..395cb0a
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DABSTRACTUNITFORMATTER_H
+#define DABSTRACTUNITFORMATTER_H
+
+#include "dtkcore_global.h"
+
+#include <QPair>
+#include <QList>
+
+DCORE_BEGIN_NAMESPACE
+
+class DAbstractUnitFormatter
+{
+public:
+    DAbstractUnitFormatter();
+    ~DAbstractUnitFormatter();
+
+protected:
+    virtual int unitMax() const = 0;
+    virtual int unitMin() const = 0;
+    virtual uint unitConvertRate(int unitId) const = 0;
+    virtual qreal unitValueMax(int unitId) const { return unitConvertRate(unitId) - 1; }
+    virtual qreal unitValueMin(int unitId) const { Q_UNUSED(unitId); return 1; }
+    virtual QString unitStr(int unitId) const = 0;
+
+public:
+    qreal formatAs(qreal value, int currentUnit, const int targetUnit) const;
+    QPair<qreal, int> format(const qreal value, const int unit) const;
+    QList<QPair<qreal, int>> formatAsUnitList(const qreal value, int unit) const;
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DABSTRACTUNITFORMATTER_H
diff --git a/src/util/ddisksizeformatter.cpp b/src/util/ddisksizeformatter.cpp
new file mode 100644 (file)
index 0000000..fbd9806
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ddisksizeformatter.h"
+
+#include <QString>
+
+DCORE_BEGIN_NAMESPACE
+
+DDiskSizeFormatter::DDiskSizeFormatter()
+    : DAbstractUnitFormatter()
+{
+
+}
+
+QString DDiskSizeFormatter::unitStr(int unitId) const
+{
+    switch (unitId)
+    {
+    case B:     return QStringLiteral("B");
+    case K:     return QStringLiteral("KB");
+    case M:     return QStringLiteral("MB");
+    case G:     return QStringLiteral("GB");
+    case T:     return QStringLiteral("TB");
+    }
+
+    return QString();
+}
+
+DDiskSizeFormatter DDiskSizeFormatter::rate(int rate)
+{
+    m_rate = rate;
+
+    return *this;
+}
+
+DCORE_END_NAMESPACE
diff --git a/src/util/ddisksizeformatter.h b/src/util/ddisksizeformatter.h
new file mode 100644 (file)
index 0000000..de7d7d7
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DISKSIZEFORMATTER_H
+#define DISKSIZEFORMATTER_H
+
+#include "dabstractunitformatter.h"
+
+DCORE_BEGIN_NAMESPACE
+
+class DDiskSizeFormatter : public DAbstractUnitFormatter
+{
+public:
+    DDiskSizeFormatter();
+
+    enum DiskUnits
+    {
+        B,
+        K,
+        M,
+        G,
+        T,
+    };
+
+    QString unitStr(int unitId) const override;
+
+    DDiskSizeFormatter rate(int rate);
+
+protected:
+    int unitMin() const override { return B; }
+    int unitMax() const override { return T; }
+    uint unitConvertRate(int unitId) const override { Q_UNUSED(unitId); return m_rate; }
+
+private:
+    int m_rate = 1000;
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DISKSIZEFORMATTER_H
diff --git a/src/util/dtimeunitformatter.cpp b/src/util/dtimeunitformatter.cpp
new file mode 100644 (file)
index 0000000..79cc831
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dtimeunitformatter.h"
+
+#include <QString>
+
+DCORE_BEGIN_NAMESPACE
+
+DTimeUnitFormatter::DTimeUnitFormatter()
+    : DAbstractUnitFormatter()
+{
+
+}
+
+uint DTimeUnitFormatter::unitConvertRate(int unitId) const
+{
+    switch (unitId)
+    {
+    case Seconds:   return 60;
+    case Minute:    return 60;
+    case Hour:      return 24;
+    default:;
+    }
+
+    return 0;
+}
+
+QString DTimeUnitFormatter::unitStr(int unitId) const
+{
+    switch (unitId)
+    {
+    case Seconds:   return QStringLiteral("s");
+    case Minute:    return QStringLiteral("m");
+    case Hour:      return QStringLiteral("h");
+    case Day:       return QStringLiteral("d");
+    default:;
+    }
+
+    return QString();
+}
+
+DCORE_END_NAMESPACE
diff --git a/src/util/dtimeunitformatter.h b/src/util/dtimeunitformatter.h
new file mode 100644 (file)
index 0000000..3c71bb8
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DTIMEUNITFORMATTER_H
+#define DTIMEUNITFORMATTER_H
+
+#include "dabstractunitformatter.h"
+
+DCORE_BEGIN_NAMESPACE
+
+class DTimeUnitFormatter : public DAbstractUnitFormatter
+{
+public:
+    DTimeUnitFormatter();
+
+    enum TimeUnits
+    {
+        Seconds,
+        Minute,
+        Hour,
+        Day,
+    };
+
+    QString unitStr(int unitId) const override;
+
+protected:
+    int unitMax() const override { return Day; }
+    int unitMin() const override { return Seconds; }
+    uint unitConvertRate(int unitId) const override;
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DTIMEUNITFORMATTER_H
index eee15ce83f132e82676cb2caf4c47bc01306eecb..60eaaa154aded0f6b6c6c557c9271a2ee45bec69 100644 (file)
@@ -1,6 +1,9 @@
 HEADERS += \
     $$PWD/dutil.h \
-    $$PWD/dpinyin.h
+    $$PWD/dpinyin.h \
+    $$PWD/dtimeunitformatter.h \
+    $$PWD/dabstractunitformatter.h \
+    $$PWD/ddisksizeformatter.h
 
 includes.files += $$PWD/*.h
 includes.files += \
@@ -9,3 +12,8 @@ includes.files += \
 
 RESOURCES += \
     $$PWD/util.qrc
+
+SOURCES += \
+    $$PWD/dtimeunitformatter.cpp \
+    $$PWD/dabstractunitformatter.cpp \
+    $$PWD/ddisksizeformatter.cpp
index a4fce037d8e0a8561116ee54a4b84a3f15276692..0cff403e0e39ab5a8126847632199d5a0f595575 100644 (file)
@@ -25,6 +25,8 @@
 #include "log/LogManager.h"
 #include "filesystem/dpathbuf.h"
 #include "singletontester.h"
+#include "util/dtimeunitformatter.h"
+#include "util/ddisksizeformatter.h"
 
 DCORE_USE_NAMESPACE
 
@@ -76,3 +78,79 @@ void TestDUtil::testDSingleton()
     QThread::sleep(5);
 }
 
+void TestDUtil::testTimeFormatter()
+{
+    const DTimeUnitFormatter timeFormatter;
+
+    // 3600 seconds == 1 hour
+    const auto r0 = timeFormatter.format(3600, DTimeUnitFormatter::Seconds);
+    Q_ASSERT(r0.first == 1 && r0.second == DTimeUnitFormatter::Hour);
+
+    // 86400 seconds == 1 day
+    const auto r1 = timeFormatter.format(86400, DTimeUnitFormatter::Seconds);
+    Q_ASSERT(r1.first == 1 && r1.second == DTimeUnitFormatter::Day);
+
+    // 129600 seconds == 1.5 day
+    const auto r3 = timeFormatter.format(129600, DTimeUnitFormatter::Seconds);
+    Q_ASSERT(qFuzzyCompare(1.5, r3.first) && r3.second == DTimeUnitFormatter::Day);
+
+    // 1.5 day == 36 hours
+    const auto r4 = timeFormatter.formatAs(1.5, DTimeUnitFormatter::Day, DTimeUnitFormatter::Hour);
+    Q_ASSERT(r4 == 36);
+}
+
+void TestDUtil::testTimeFormatterList()
+{
+    const DTimeUnitFormatter timeFormatter;
+
+    // 135120.5 Minutes == 93 days + 20 hours + 30 seconds
+    const auto r = timeFormatter.formatAsUnitList(135120.5, DTimeUnitFormatter::Minute);
+    Q_ASSERT(r[0].first == 93 && r[0].second == DTimeUnitFormatter::Day);
+    Q_ASSERT(r[1].first == 20 && r[1].second == DTimeUnitFormatter::Hour);
+    Q_ASSERT(r[2].first == 30 && r[2].second == DTimeUnitFormatter::Seconds);
+}
+
+void TestDUtil::testDiskFormatter()
+{
+    const DDiskSizeFormatter diskFormatter1000 = DDiskSizeFormatter();
+
+    // 1000 K == 1 M
+    const auto i0 = diskFormatter1000.format(1000, DDiskSizeFormatter::K);
+    Q_ASSERT(i0.first == 1 && i0.second == DDiskSizeFormatter::M);
+
+    // 1000 K == 1000000 B
+    const auto i1 = diskFormatter1000.formatAs(1000, DDiskSizeFormatter::K, DDiskSizeFormatter::B);
+    Q_ASSERT(i1 == 1000000);
+}
+
+void TestDUtil::testDiskFormatterList()
+{
+    const DDiskSizeFormatter diskFormatter = DDiskSizeFormatter();
+
+    // 1351223412.1234 KB == 1 TB + 351 GB + 223 MB + 412 KB + 123.4 B
+    const auto r = diskFormatter.formatAsUnitList(1351223412.1234, DDiskSizeFormatter::K);
+    Q_ASSERT(r[0].first == 1 && r[0].second == DDiskSizeFormatter::T);
+    Q_ASSERT(r[1].first == 351 && r[1].second == DDiskSizeFormatter::G);
+    Q_ASSERT(r[2].first == 223 && r[2].second == DDiskSizeFormatter::M);
+    Q_ASSERT(r[3].first == 412 && r[3].second == DDiskSizeFormatter::K);
+
+    // TODO: test failed
+//    Q_ASSERT(r[4].first == 123.4 && r[4].second == DiskSizeFormatter::B);
+}
+
+void TestDUtil::testDiskFormatter1024()
+{
+    const DDiskSizeFormatter diskFormatter = DDiskSizeFormatter().rate(1024);
+
+    // 1024 K == 1 M
+    const auto d0 = diskFormatter.format(1024, DDiskSizeFormatter::K);
+    Q_ASSERT(d0.first == 1 && d0.second == DDiskSizeFormatter::M);
+
+    // 100000000000 B == 93.13225746154785 G
+    const auto d1 = diskFormatter.format(100000000000, DDiskSizeFormatter::B);
+    Q_ASSERT(qFuzzyCompare(93.13225746154785, d1.first) && d1.second == DDiskSizeFormatter::G);
+
+    // 100000000000 B == 0.09094947017729282 T
+    const auto d2 = diskFormatter.formatAs(100000000000, DDiskSizeFormatter::B, DDiskSizeFormatter::T);
+    Q_ASSERT(qFuzzyCompare(0.09094947017729282, d2));
+}
index 2fddddf33974b2c2bca035fd23e65d1599a19719..cab11cc583514fe1977748034899c186ebabd737 100644 (file)
@@ -30,6 +30,11 @@ private Q_SLOTS:
     void testLogPath();
     void testPathChange();
     void testDSingleton();
+    void testTimeFormatter();
+    void testTimeFormatterList();
+    void testDiskFormatter();
+    void testDiskFormatterList();
+    void testDiskFormatter1024();
 };
 
 #endif // DUTILTESTER_H