Qt with Cascades UI Examples Documentation

WordCount.cpp Example File

wordcount/src/WordCount.cpp
    /****************************************************************************
     **
     ** Portions Copyright (C) 2012 Research In Motion Limited.
     ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
     ** All rights reserved.
     ** Contact: Research In Motion Ltd. (http://www.rim.com/company/contact/)
     ** Contact: Nokia Corporation (qt-info@nokia.com)
     **
     ** This file is part of the examples of the BB10 Platform and is derived
     ** from a similar file that is part of the Qt Toolkit.
     **
     ** You may use this file under the terms of the BSD license as follows:
     **
     ** "Redistribution and use in source and binary forms, with or without
     ** modification, are permitted provided that the following conditions are
     ** met:
     **   * Redistributions of source code must retain the above copyright
     **     notice, this list of conditions and the following disclaimer.
     **   * Redistributions in binary form must reproduce the above copyright
     **     notice, this list of conditions and the following disclaimer in
     **     the documentation and/or other materials provided with the
     **     distribution.
     **   * Neither the name of Research In Motion, nor the name of Nokia
     **     Corporation and its Subsidiary(-ies), nor the names of its
     **     contributors may be used to endorse or promote products
     **     derived from this software without specific prior written
     **     permission.
     **
     ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
     **
     ****************************************************************************/

    #include "WordCount.hpp"

    #include <QtCore/QDir>
    #include <QtCore/QFile>
    #include <QtCore/QTime>
    #include <qtconcurrentmap.h>

    #include <numeric> // for std::accumulate

    /**
     * A helper structure that maps the name of a file
     * to the number of words it contains.
     */
    typedef QMap<QString, int> WordCountMap;

    /**
     * A function that counts words single threaded
     * by iterating over the files sequentially.
     */
    WordCountMap singleThreadedWordCount(const QStringList &files)
    {
        WordCountMap wordCount;

        foreach (const QString &fileName, files) {
            QFile file(fileName);
            file.open(QIODevice::ReadOnly);
            QTextStream textStream(&file);
            while (textStream.atEnd() == false) {
                foreach(const QString &word, textStream.readLine().split(" "))
                    wordCount[word] += 1;
            }
        }

        return wordCount;
    }

    /**
     * A function that counts the words in a single file.
     * This function is called in parallel by several threads, therefor it
     * must be thread safe.
     */
    WordCountMap countWords(const QString &fileName)
    {
        QFile file(fileName);
        file.open(QIODevice::ReadOnly);
        QTextStream textStream(&file);
        WordCountMap wordCount;

        while (textStream.atEnd() == false) {
            foreach (const QString &word, textStream.readLine().split(" "))
                wordCount[word] += 1;
        }

        return wordCount;
    }

    /**
     * A function that adds the results from the map to the final
     * result. This functor will only be called by one thread at a time.
     */
    void reduce(WordCountMap &result, const WordCountMap &w)
    {
        QMapIterator<QString, int> i(w);
        while (i.hasNext()) {
            i.next();
            result[i.key()] += i.value();
        }
    }

    WordCount::WordCount()
        : m_wordCount(0), m_elapsedTime(0), m_active(false)
    {
        // Find a couple of files in the file system
        m_files = findFiles("/usr/photon/", QStringList() << "*");
        m_files += findFiles("/scripts/", QStringList() << "*");

        emit fileCountChanged();
    }

    int WordCount::fileCount() const
    {
        return m_files.count();
    }

    int WordCount::wordCount() const
    {
        return m_wordCount;
    }

    int WordCount::elapsedTime() const
    {
        return m_elapsedTime;
    }

    bool WordCount::active() const
    {
        return m_active;
    }

    void WordCount::countSingleThreaded()
    {
        // Mark the application as active
        m_active = true;
        emit activeChanged();

        // Start to measure the time
        QTime time;
        time.start();

        // Count the words single threaded
        const WordCountMap total = singleThreadedWordCount(m_files);

        // Update the measured time
        m_elapsedTime = time.elapsed();
        emit elapsedTimeChanged();

        // Accumulate the per-file word counts to the total word count
        const QList<int> counts = total.values();
        m_wordCount = std::accumulate(counts.begin(), counts.end(), 0);
        emit wordCountChanged();

        // Mark the application as inactive
        m_active = false;
        emit activeChanged();
    }

    void WordCount::countMultiThreaded()
    {
        // Mark the application as active
        m_active = true;
        emit activeChanged();

        // Start to measure the time
        QTime time;
        time.start();

        // Count the words multi-threaded by using QtConcurrent
        const WordCountMap total = QtConcurrent::mappedReduced(m_files, countWords, reduce);

        // Update the measured time
        m_elapsedTime = time.elapsed();
        emit elapsedTimeChanged();

        // Accumulate the per-file word counts to the total word count
        const QList<int> counts = total.values();
        m_wordCount = std::accumulate(counts.begin(), counts.end(), 0);
        emit wordCountChanged();

        // Mark the application as inactive
        m_active = false;
        emit activeChanged();
    }

    QStringList WordCount::findFiles(const QString &startDir, const QStringList &filters)
    {
        QStringList names;
        QDir dir(startDir);

        // Collect all files from local dir that match the filter
        foreach (const QString &file, dir.entryList(filters, QDir::Files))
            names += startDir + "/" + file;

        // Iterate over sub-directories
        foreach (const QString &subdir, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot))
            names += findFiles(startDir + "/" + subdir, filters);

        return names;
    }