<commit_before>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <algorithm>
#include <iostream>     // TODO: Remove this temporary include.
#include <math.h>
#include <ostream>

#include "BitFunnel/BitFunnelTypes.h"
#include "BitFunnel/Exceptions.h"
#include "BitFunnel/Index/Factories.h"
#include "BitFunnel/Index/IFactSet.h"
#include "BitFunnel/Index/ITermTable.h"
#include "BitFunnel/Index/ITermTreatment.h"
#include "BitFunnel/Utilities/Stopwatch.h"
#include "DocumentFrequencyTable.h"
#include "TermTableBuilder.h"

namespace BitFunnel
{
    //*************************************************************************
    //
    // Factory methods.
    //
    //*************************************************************************
    std::unique_ptr<ITermTableBuilder>
        Factories::CreateTermTableBuilder(double density,
                                          double adhocFrequency,
                                          ITermTreatment const & treatment,
                                          IDocumentFrequencyTable const & terms,
                                          IFactSet const & facts,
                                          ITermTable & termTable)
    {
        return
            std::unique_ptr<ITermTableBuilder>(new TermTableBuilder(density,
                                                                    adhocFrequency,
                                                                    treatment,
                                                                    terms,
                                                                    facts,
                                                                    termTable));
    }

    //*************************************************************************
    //
    // TermTableBuilder
    //
    //*************************************************************************
    TermTableBuilder::TermTableBuilder(double density,
                                       double adhocFrequency,
                                       ITermTreatment const & treatment,
                                       IDocumentFrequencyTable const & terms,
                                       IFactSet const & facts,
                                       ITermTable & termTable)
        : m_termTable(termTable),
          m_buildTime(0.0)
    {
        Stopwatch stopwatch;

        // Create one RowAssigner for each rank.
        for (Rank rank = 0; rank <= c_maxRankValue; ++rank)
        {
            m_rowAssigners.push_back(
                std::unique_ptr<RowAssigner>(
                    new RowAssigner(rank,
                                    density,
                                    termTable)));
        }

        // For each entry in the document frequency table.
        // (note that the entries are sorted in order of decreasing frequency).
        for (auto dfEntry : terms)
        {
            // TODO: Consider handling disposed terms here.

            //std::cout << "Term: ";
            //dfEntry.GetTerm().Print(std::cout);
            //std::cout << "; frequency = " << dfEntry.GetFrequency() << std::endl;

            // Get the term's RowConfiguration.
            auto configuration = treatment.GetTreatment(dfEntry.GetTerm());

            if (dfEntry.GetFrequency() < adhocFrequency)
            {
                // For each rank entry in the RowConfiguration.
                for (auto rcEntry : configuration)
                {
                    // Assign the appropriate rows.
                    m_rowAssigners[rcEntry.GetRank()]->AssignAdhoc(dfEntry.GetFrequency(),
                                                                   rcEntry.GetRowCount());
                }
            }
            else
            {
                m_termTable.OpenTerm();

                //std::cout << "  Configuration: ";
                //configuration.Write(std::cout);
                //std::cout << std::endl;

                // For each rank entry in the RowConfiguration.
                for (auto rcEntry : configuration)
                {
                    // Assign the appropriate rows.
                    m_rowAssigners[rcEntry.GetRank()]->AssignExplicit(dfEntry.GetFrequency(),
                                                                      rcEntry.GetRowCount(),
                                                                      rcEntry.IsPrivate());
                }

                m_termTable.CloseTerm(dfEntry.GetTerm().GetRawHash());
            }
        }

        // TODO: make entries for facts.

        // For each (IdfX10, GramSize) pair.
        for (Term::IdfX10 idf = 0; idf <= Term::c_maxIdfX10Value; ++idf)
        {
            for (Term::GramSize gramSize = 1; gramSize < Term::c_maxGramSize; ++gramSize)
            {
                const Term::Hash hash = 0ull;
                const Term::StreamId streamId = 0;

                m_termTable.OpenTerm();

                Term term(hash, streamId, idf, gramSize);
                auto configuration = treatment.GetTreatment(term);
                for (auto rcEntry : configuration)
                {
                    for (size_t i = 0; i < rcEntry.GetRowCount(); ++i)
                    {
                        // Third parameter of RowId() denotes adhoc row.
                        m_termTable.AddRowId(RowId(rcEntry.GetRank(), 0u, true));
                    }
                }

                m_termTable.CloseAdhocTerm(idf, gramSize);
            }
        }

        for (Rank rank = 0; rank <= c_maxRankValue; ++rank)
        {
            // TODO: Come up with a more principled solution.
            // When building a TermTable based on a small IDocumentFrequencyTable,
            // the builder may run into a situation where it encounters no adhoc
            // terms (because all terms encountered are in the frequency table,
            // and therefore treated as explicit).
            //
            // This could be a problem when ingesting a corpus that has adhoc terms
            // since the TermTable would not be configured with adhoc rows. A
            // TermTable with zero adhoc rows will cause a divide-by-zero when
            // attempting to compute a RowIndex by taking the mod of the hash and
            // zero.
            //
            // To avoid this problem, the TermTableBuilder always configures ranks
            // that are used in the ITermTreatment with some minimal amount of
            // adhoc rows. GetMinAdhocRowCount() returns this minimal number.
            //
            // Note that this approach also ensures there are sufficient adhoc rows
            // to greatly reduce the chances that a single adhoc term will have
            // duplicate rows.
            // https://github.com/BitFunnel/BitFunnel/issues/155

            size_t adhocRowCount = m_rowAssigners[rank]->GetAdhocRowCount();
            if (m_termTable.IsRankUsed(rank))
            {
                adhocRowCount = std::max(adhocRowCount, GetMinAdhocRowCount());
            }
            m_termTable.SetRowCounts(rank,
                                     m_rowAssigners[rank]->GetExplicitRowCount(),
                                     adhocRowCount);
        }

        m_termTable.SetFactCount(facts.GetCount());

        m_termTable.Seal();

        m_buildTime = stopwatch.ElapsedTime();
    }

    void TermTableBuilder::Print(std::ostream& output) const
    {
        output << "Total build time: " << m_buildTime << " seconds." << std::endl;

        for (auto&& assigner : m_rowAssigners)
        {
            assigner->Print(output);
        }
    }

    // TODO: Come up with a more principled solution.
    // When building a TermTable based on a small IDocumentFrequencyTable,
    // the builder may run into a situation where it encounters no adhoc
    // terms (because all terms encountered are in the frequency table,
    // and therefore treated as explicit).
    //
    // This could be a problem when ingesting a corpus that has adhoc terms
    // since the TermTable would not be configured with adhoc rows. A
    // TermTable with zero adhoc rows will cause a divide-by-zero when
    // attempting to compute a RowIndex by taking the mod of the hash and
    // zero.
    //
    // To avoid this problem, the TermTableBuilder always configures ranks
    // that are used in the ITermTreatment with some minimal amount of
    // adhoc rows. GetMinAdhocRowCount() returns this minimal number.
    //
    // Note that this approach also ensures there are sufficient adhoc rows
    // to greatly reduce the chances that a single adhoc term will have
    // duplicate rows.
    // https://github.com/BitFunnel/BitFunnel/issues/155
    size_t TermTableBuilder::GetMinAdhocRowCount()
    {
        const size_t c_minAdhocRowCount = 1000ull;
        return c_minAdhocRowCount;
    }

    //*************************************************************************
    //
    // TermTableBuilder::RowAssigner
    //
    //*************************************************************************
    TermTableBuilder::RowAssigner::RowAssigner(
        Rank rank,
        double density,
        ITermTable & termTable)
        : m_rank(rank),
          m_density(density),
          m_termTable(termTable),
          m_adhocTotal(0),
          m_currentRow(0),
          m_explicitTermCount(0),
          m_adhocTermCount(0),
          m_privateTermCount(0),
          m_privateRowCount(0)
    {
        // TODO: Is there a way to reduce this coupling between RowAssigner
        // and the internals of TermTable?
        // Reserve first SystemTerm::Count rows for system rows like soft
        // deleted, match all, and match none.
        if (rank == 0)
        {
            m_currentRow = ITermTable::SystemTerm::Count;
        }
    }

    void TermTableBuilder::RowAssigner::AssignExplicit(double frequency,
                                                       RowIndex count,
                                                       bool isPrivate)
    {
        // Compute the frequency at rank.
        double f = Term::FrequencyAtRank(frequency, m_rank);

        if (isPrivate || f >= m_density)
        {
            // A private row was requested or this term was found to have
            // sufficient frequency to warrant a private row.
            // Since the row is private (i.e. not shared with other terms)
            // we only need a single row, even if count > 1.

            ++m_privateTermCount;
            ++m_privateRowCount;

            // Just reserve the RowIndex and then add the appropriate RowID to
            // the TermTableBuilder.
            m_termTable.AddRowId(RowId(m_rank, m_currentRow++));
        }
        else
        {
            // This is an explicit term. In other words, it sets enough bits
            // that it must be bin-packed into its rows.
            ++m_explicitTermCount;

            // Use the Best Fit Descreasing bin packing algorithm.
            // See https://www.cs.ucsb.edu/~suri/cs130b/BinPacking.txt.

            // currentBins holds bins assigned for this term.
            std::vector<Bin> currentBins;

            for (RowIndex i = 0; i < count; ++i)
            {
                // Look for an existing bin with enough space.
                auto it = m_bins.lower_bound(Bin(f));
                if (it == m_bins.end())
                {
                    // No existing bin has enough space. Start a new bin.
                    currentBins.push_back(Bin(m_density, f, m_currentRow++));
                }
                else
                {
                    // Found a bin with enough space.
                    Bin bin = *it;

                    // Remove this bin from m_bins since we will be updating
                    // its space.
                    m_bins.erase(it);

                    // Reserve space in this bin for term.
                    bin.Reserve(f);

                    // Add to bins associated with this term.
                    // DESIGN NOTE: we can't immediately reinsert bin into
                    // m_bins because we must ensure that all bins for this
                    // term are unique. If we reinserted bin at this point,
                    // the call to m_bins.lower_bound() might return it on
                    // a future iteration.
                    currentBins.push_back(bin);
                }
            }

            // All of the bins for this term have been identified.

            // Now add the appropriate RowIds to the TermTable.
            for (auto b : currentBins)
            {
                // TODO: figure out ShardId value here.
                m_termTable.AddRowId(RowId(m_rank, b.GetIndex()));
            }

            // Reinsert the bins into m_bins.
            m_bins.insert(currentBins.begin(), currentBins.end());
        }
    }

    void TermTableBuilder::RowAssigner::AssignAdhoc(double frequency,
                                                    RowIndex count)
    {
        // This is an adhoc term whose location is defined by a set of
        // hash functions.
        ++m_adhocTermCount;

        // Update m_adhocTotal with this term's contribution to the total
        // number of bits.
        m_adhocTotal += frequency * count;
    }

    RowIndex TermTableBuilder::RowAssigner::GetExplicitRowCount() const
    {
        return m_currentRow;
    }

    RowIndex TermTableBuilder::RowAssigner::GetAdhocRowCount() const
    {
        double rowCount = ceil(m_adhocTotal / m_density);
        if (rowCount > c_maxRowIndexValue)
        {
            FatalError
                error("TermTableBuilder::RowAssigner::GetAdhocRowCount: too many rows.");
            throw error;
        }

        return static_cast<RowIndex>(rowCount);
    }

    void TermTableBuilder::RowAssigner::Print(std::ostream& output) const
    {
        output << "===================================" << std::endl;
        output << "RowAssigner for rank " << m_rank << std::endl;

        if (m_explicitTermCount + m_adhocTermCount == 0)
        {
            output << "  No terms" << std::endl;
        }
        else
        {
            output << "  Terms" << std::endl;
            output << "    Total: "
                   << m_adhocTermCount + m_explicitTermCount + m_privateTermCount
                   << std::endl;
            output << "    Adhoc: " << m_adhocTermCount << std::endl;
            output << "    Explicit: " << m_explicitTermCount << std::endl;
            output << "    Private: " << m_privateTermCount << std::endl;

            output << std::endl;

            output << "  Rows" << std::endl;
            output << "    Total: " << GetAdhocRowCount() + m_currentRow
                   << std::endl;
            output << "    Adhoc: " << GetAdhocRowCount() << std::endl;
            output << "    Explicit: " << m_bins.size() << std::endl;
            output << "    Private: " << m_privateRowCount << std::endl;
            output << std::endl;

            output << "  Bytes per document: "
                   << m_termTable.GetBytesPerDocument(m_rank) << std::endl;

            output << std::endl;

            Accumulator a;
            for (auto bin : m_bins)
            {
                a.Record(bin.GetFrequency(m_density));
            }

            output << std::endl;

            output << "  Densities in explicit shared rows" << std::endl;
            output << "    Mean: " << a.GetMean() << std::endl;
            output << "    Min: " << a.GetMin() << std::endl;
            output << "    Max: " << a.GetMax() << std::endl;
            output << "    Variance: " << a.GetVariance() << std::endl;
        }

        output << std::endl;
    }
}
<commit_msg>Fix bug in RowAssigner::AssignAdhoc() which leads to overdensity.<commit_after>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <algorithm>
#include <iostream>     // TODO: Remove this temporary include.
#include <math.h>
#include <ostream>

#include "BitFunnel/BitFunnelTypes.h"
#include "BitFunnel/Exceptions.h"
#include "BitFunnel/Index/Factories.h"
#include "BitFunnel/Index/IFactSet.h"
#include "BitFunnel/Index/ITermTable.h"
#include "BitFunnel/Index/ITermTreatment.h"
#include "BitFunnel/Utilities/Stopwatch.h"
#include "DocumentFrequencyTable.h"
#include "TermTableBuilder.h"

namespace BitFunnel
{
    //*************************************************************************
    //
    // Factory methods.
    //
    //*************************************************************************
    std::unique_ptr<ITermTableBuilder>
        Factories::CreateTermTableBuilder(double density,
                                          double adhocFrequency,
                                          ITermTreatment const & treatment,
                                          IDocumentFrequencyTable const & terms,
                                          IFactSet const & facts,
                                          ITermTable & termTable)
    {
        return
            std::unique_ptr<ITermTableBuilder>(new TermTableBuilder(density,
                                                                    adhocFrequency,
                                                                    treatment,
                                                                    terms,
                                                                    facts,
                                                                    termTable));
    }

    //*************************************************************************
    //
    // TermTableBuilder
    //
    //*************************************************************************
    TermTableBuilder::TermTableBuilder(double density,
                                       double adhocFrequency,
                                       ITermTreatment const & treatment,
                                       IDocumentFrequencyTable const & terms,
                                       IFactSet const & facts,
                                       ITermTable & termTable)
        : m_termTable(termTable),
          m_buildTime(0.0)
    {
        Stopwatch stopwatch;

        // Create one RowAssigner for each rank.
        for (Rank rank = 0; rank <= c_maxRankValue; ++rank)
        {
            m_rowAssigners.push_back(
                std::unique_ptr<RowAssigner>(
                    new RowAssigner(rank,
                                    density,
                                    termTable)));
        }

        // For each entry in the document frequency table.
        // (note that the entries are sorted in order of decreasing frequency).
        for (auto dfEntry : terms)
        {
            // TODO: Consider handling disposed terms here.

            //std::cout << "Term: ";
            //dfEntry.GetTerm().Print(std::cout);
            //std::cout << "; frequency = " << dfEntry.GetFrequency() << std::endl;

            // Get the term's RowConfiguration.
            auto configuration = treatment.GetTreatment(dfEntry.GetTerm());

            if (dfEntry.GetFrequency() < adhocFrequency)
            {
                // For each rank entry in the RowConfiguration.
                for (auto rcEntry : configuration)
                {
                    // Assign the appropriate rows.
                    m_rowAssigners[rcEntry.GetRank()]->AssignAdhoc(dfEntry.GetFrequency(),
                                                                   rcEntry.GetRowCount());
                }
            }
            else
            {
                m_termTable.OpenTerm();

                //std::cout << "  Configuration: ";
                //configuration.Write(std::cout);
                //std::cout << std::endl;

                // For each rank entry in the RowConfiguration.
                for (auto rcEntry : configuration)
                {
                    // Assign the appropriate rows.
                    m_rowAssigners[rcEntry.GetRank()]->AssignExplicit(dfEntry.GetFrequency(),
                                                                      rcEntry.GetRowCount(),
                                                                      rcEntry.IsPrivate());
                }

                m_termTable.CloseTerm(dfEntry.GetTerm().GetRawHash());
            }
        }

        // TODO: make entries for facts.

        // For each (IdfX10, GramSize) pair.
        for (Term::IdfX10 idf = 0; idf <= Term::c_maxIdfX10Value; ++idf)
        {
            for (Term::GramSize gramSize = 1; gramSize < Term::c_maxGramSize; ++gramSize)
            {
                const Term::Hash hash = 0ull;
                const Term::StreamId streamId = 0;

                m_termTable.OpenTerm();

                Term term(hash, streamId, idf, gramSize);
                auto configuration = treatment.GetTreatment(term);
                for (auto rcEntry : configuration)
                {
                    for (size_t i = 0; i < rcEntry.GetRowCount(); ++i)
                    {
                        // Third parameter of RowId() denotes adhoc row.
                        m_termTable.AddRowId(RowId(rcEntry.GetRank(), 0u, true));
                    }
                }

                m_termTable.CloseAdhocTerm(idf, gramSize);
            }
        }

        for (Rank rank = 0; rank <= c_maxRankValue; ++rank)
        {
            // TODO: Come up with a more principled solution.
            // When building a TermTable based on a small IDocumentFrequencyTable,
            // the builder may run into a situation where it encounters no adhoc
            // terms (because all terms encountered are in the frequency table,
            // and therefore treated as explicit).
            //
            // This could be a problem when ingesting a corpus that has adhoc terms
            // since the TermTable would not be configured with adhoc rows. A
            // TermTable with zero adhoc rows will cause a divide-by-zero when
            // attempting to compute a RowIndex by taking the mod of the hash and
            // zero.
            //
            // To avoid this problem, the TermTableBuilder always configures ranks
            // that are used in the ITermTreatment with some minimal amount of
            // adhoc rows. GetMinAdhocRowCount() returns this minimal number.
            //
            // Note that this approach also ensures there are sufficient adhoc rows
            // to greatly reduce the chances that a single adhoc term will have
            // duplicate rows.
            // https://github.com/BitFunnel/BitFunnel/issues/155

            size_t adhocRowCount = m_rowAssigners[rank]->GetAdhocRowCount();
            if (m_termTable.IsRankUsed(rank))
            {
                adhocRowCount = std::max(adhocRowCount, GetMinAdhocRowCount());
            }
            m_termTable.SetRowCounts(rank,
                                     m_rowAssigners[rank]->GetExplicitRowCount(),
                                     adhocRowCount);
        }

        m_termTable.SetFactCount(facts.GetCount());

        m_termTable.Seal();

        m_buildTime = stopwatch.ElapsedTime();
    }

    void TermTableBuilder::Print(std::ostream& output) const
    {
        output << "Total build time: " << m_buildTime << " seconds." << std::endl;

        for (auto&& assigner : m_rowAssigners)
        {
            assigner->Print(output);
        }
    }

    // TODO: Come up with a more principled solution.
    // When building a TermTable based on a small IDocumentFrequencyTable,
    // the builder may run into a situation where it encounters no adhoc
    // terms (because all terms encountered are in the frequency table,
    // and therefore treated as explicit).
    //
    // This could be a problem when ingesting a corpus that has adhoc terms
    // since the TermTable would not be configured with adhoc rows. A
    // TermTable with zero adhoc rows will cause a divide-by-zero when
    // attempting to compute a RowIndex by taking the mod of the hash and
    // zero.
    //
    // To avoid this problem, the TermTableBuilder always configures ranks
    // that are used in the ITermTreatment with some minimal amount of
    // adhoc rows. GetMinAdhocRowCount() returns this minimal number.
    //
    // Note that this approach also ensures there are sufficient adhoc rows
    // to greatly reduce the chances that a single adhoc term will have
    // duplicate rows.
    // https://github.com/BitFunnel/BitFunnel/issues/155
    size_t TermTableBuilder::GetMinAdhocRowCount()
    {
        const size_t c_minAdhocRowCount = 1000ull;
        return c_minAdhocRowCount;
    }

    //*************************************************************************
    //
    // TermTableBuilder::RowAssigner
    //
    //*************************************************************************
    TermTableBuilder::RowAssigner::RowAssigner(
        Rank rank,
        double density,
        ITermTable & termTable)
        : m_rank(rank),
          m_density(density),
          m_termTable(termTable),
          m_adhocTotal(0),
          m_currentRow(0),
          m_explicitTermCount(0),
          m_adhocTermCount(0),
          m_privateTermCount(0),
          m_privateRowCount(0)
    {
        // TODO: Is there a way to reduce this coupling between RowAssigner
        // and the internals of TermTable?
        // Reserve first SystemTerm::Count rows for system rows like soft
        // deleted, match all, and match none.
        if (rank == 0)
        {
            m_currentRow = ITermTable::SystemTerm::Count;
        }
    }

    void TermTableBuilder::RowAssigner::AssignExplicit(double frequency,
                                                       RowIndex count,
                                                       bool isPrivate)
    {
        // Compute the frequency at rank.
        double f = Term::FrequencyAtRank(frequency, m_rank);

        if (isPrivate || f >= m_density)
        {
            // A private row was requested or this term was found to have
            // sufficient frequency to warrant a private row.
            // Since the row is private (i.e. not shared with other terms)
            // we only need a single row, even if count > 1.

            ++m_privateTermCount;
            ++m_privateRowCount;

            // Just reserve the RowIndex and then add the appropriate RowID to
            // the TermTableBuilder.
            m_termTable.AddRowId(RowId(m_rank, m_currentRow++));
        }
        else
        {
            // This is an explicit term. In other words, it sets enough bits
            // that it must be bin-packed into its rows.
            ++m_explicitTermCount;

            // Use the Best Fit Descreasing bin packing algorithm.
            // See https://www.cs.ucsb.edu/~suri/cs130b/BinPacking.txt.

            // currentBins holds bins assigned for this term.
            std::vector<Bin> currentBins;

            for (RowIndex i = 0; i < count; ++i)
            {
                // Look for an existing bin with enough space.
                auto it = m_bins.lower_bound(Bin(f));
                if (it == m_bins.end())
                {
                    // No existing bin has enough space. Start a new bin.
                    currentBins.push_back(Bin(m_density, f, m_currentRow++));
                }
                else
                {
                    // Found a bin with enough space.
                    Bin bin = *it;

                    // Remove this bin from m_bins since we will be updating
                    // its space.
                    m_bins.erase(it);

                    // Reserve space in this bin for term.
                    bin.Reserve(f);

                    // Add to bins associated with this term.
                    // DESIGN NOTE: we can't immediately reinsert bin into
                    // m_bins because we must ensure that all bins for this
                    // term are unique. If we reinserted bin at this point,
                    // the call to m_bins.lower_bound() might return it on
                    // a future iteration.
                    currentBins.push_back(bin);
                }
            }

            // All of the bins for this term have been identified.

            // Now add the appropriate RowIds to the TermTable.
            for (auto b : currentBins)
            {
                // TODO: figure out ShardId value here.
                m_termTable.AddRowId(RowId(m_rank, b.GetIndex()));
            }

            // Reinsert the bins into m_bins.
            m_bins.insert(currentBins.begin(), currentBins.end());
        }
    }

    void TermTableBuilder::RowAssigner::AssignAdhoc(double frequency,
                                                    RowIndex count)
    {
        // This is an adhoc term whose location is defined by a set of
        // hash functions.
        ++m_adhocTermCount;

        // Update m_adhocTotal with this term's contribution to the total
        // number of bits.
        double f = Term::FrequencyAtRank(frequency, m_rank);
        m_adhocTotal += f * count;
    }

    RowIndex TermTableBuilder::RowAssigner::GetExplicitRowCount() const
    {
        return m_currentRow;
    }

    RowIndex TermTableBuilder::RowAssigner::GetAdhocRowCount() const
    {
        double rowCount = ceil(m_adhocTotal / m_density);
        if (rowCount > c_maxRowIndexValue)
        {
            FatalError
                error("TermTableBuilder::RowAssigner::GetAdhocRowCount: too many rows.");
            throw error;
        }

        return static_cast<RowIndex>(rowCount);
    }

    void TermTableBuilder::RowAssigner::Print(std::ostream& output) const
    {
        output << "===================================" << std::endl;
        output << "RowAssigner for rank " << m_rank << std::endl;

        if (m_explicitTermCount + m_adhocTermCount == 0)
        {
            output << "  No terms" << std::endl;
        }
        else
        {
            output << "  Terms" << std::endl;
            output << "    Total: "
                   << m_adhocTermCount + m_explicitTermCount + m_privateTermCount
                   << std::endl;
            output << "    Adhoc: " << m_adhocTermCount << std::endl;
            output << "    Explicit: " << m_explicitTermCount << std::endl;
            output << "    Private: " << m_privateTermCount << std::endl;

            output << std::endl;

            output << "  Rows" << std::endl;
            output << "    Total: " << GetAdhocRowCount() + m_currentRow
                   << std::endl;
            output << "    Adhoc: " << GetAdhocRowCount() << std::endl;
            output << "    Explicit: " << m_bins.size() << std::endl;
            output << "    Private: " << m_privateRowCount << std::endl;
            output << std::endl;

            output << "  Bytes per document: "
                   << m_termTable.GetBytesPerDocument(m_rank) << std::endl;

            output << std::endl;

            Accumulator a;
            for (auto bin : m_bins)
            {
                a.Record(bin.GetFrequency(m_density));
            }

            output << std::endl;

            output << "  Densities in explicit shared rows" << std::endl;
            output << "    Mean: " << a.GetMean() << std::endl;
            output << "    Min: " << a.GetMin() << std::endl;
            output << "    Max: " << a.GetMax() << std::endl;
            output << "    Variance: " << a.GetVariance() << std::endl;
        }

        output << std::endl;
    }
}
<|endoftext|>


<commit_before>/*=========================================================================

 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/
#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"
#include "otbGenericRSTransform.h"

namespace otb
{

enum
{
  Mode_Download,
  Mode_Simulate
};

namespace Wrapper
{

class DownloadSRTMTiles : public Application
{
public:
  /** Standard class typedefs. */
  typedef DownloadSRTMTiles             Self;
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  typedef otb::GenericRSTransform<>     RSTransformType;

  typedef FloatVectorImageType::IndexType IndexType;
  typedef FloatVectorImageType::PointType PointType;
  typedef FloatVectorImageType::SizeType  SizeType;
  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(DownloadSRTMTiles, otb::Application);

private:

  void DoInit()
  {
    SetName("DownloadSRTMTiles");
    SetDescription("Download or list SRTM tiles related to images");

    // Documentation
    SetDocName("Download or list SRTM tiles related to images");
    SetDocLongDescription("Download or list SRTM tiles related to images...");
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(" ");

    AddDocTag("Utilities");
    AddDocTag(Tags::Manip);

    AddParameter(ParameterType_InputImageList,  "il",   "Input images list");
    SetParameterDescription("il", "The list of images on which you want to determine corresponding SRTM tiles.");

    // UserDefined values
    AddParameter(ParameterType_Choice, "mode", "download or simulate");
    MandatoryOn("mode");

    AddChoice("mode.download", "Download");
    SetParameterDescription("mode.download","Download.");

    AddParameter(ParameterType_OutputFilename, "mode.download.outdir", "ouput dir");
    SetParameterDescription("mode.download.outdir", "out dir");

    AddChoice("mode.simulate", "List tiles");
    SetParameterDescription("mode.simulate","List tiles");

    // Doc example parameter settings
    SetDocExampleParameterValue("il", "QB_Toulouse_Ortho_XS.tif");
    SetDocExampleParameterValue("mode", "simulate");
  }

  void DoUpdateParameters()
  {
    // Nothing to do here : all parameters are independent
  }

  void DoExecute()
  {
    // Get the input image list
    FloatVectorImageListType::Pointer inList = this->GetParameterImageList("il");

    if( inList->Size() == 0 )
      {
      itkExceptionMacro("No input Image set...");
      }

    inList->GetNthElement(0)->UpdateOutputInformation();

    std::vector<std::string> simulateTilesVector;

    for( unsigned int i=0; i<inList->Size(); i++ )
      {
      FloatVectorImageType::Pointer inImage = inList->GetNthElement(i);
      inImage->UpdateOutputInformation();

      RSTransformType::Pointer rsTransformToWGS84 = RSTransformType::New();
      rsTransformToWGS84->SetInputKeywordList(inImage->GetImageKeywordlist());
      rsTransformToWGS84->SetInputProjectionRef(inImage->GetProjectionRef());

      rsTransformToWGS84->InstanciateTransform();

      const SizeType size = inImage->GetLargestPossibleRegion().GetSize();

      PointType upperLeft;
      upperLeft[0] = 0;
      upperLeft[1] = 0;
      PointType upperLeftWGS84 = rsTransformToWGS84->TransformPoint(upperLeft);
      otbAppLogINFO(<< "upperLeftWGS84 " << upperLeftWGS84);

      PointType upperRight;
      upperRight[0] = size[0] - 1;
      upperRight[1] = 0;
      PointType upperRightWGS84 = rsTransformToWGS84->TransformPoint(upperRight);
      otbAppLogINFO(<< "upperRightWGS84 " << upperRightWGS84);

      PointType lowerLeft;
      lowerLeft[0] = 0;
      lowerLeft[1] = size[1] - 1;
      PointType lowerLeftWGS84 = rsTransformToWGS84->TransformPoint(lowerLeft);
      otbAppLogINFO(<< "lowerLeftWGS84 " << lowerLeftWGS84);

      PointType lowerRight;
      lowerRight[0] = size[0] - 1;
      lowerRight[1] = size[1] - 1;
      PointType lowerRightWGS84 = rsTransformToWGS84->TransformPoint(lowerRight);
      otbAppLogINFO(<< "lowerRightWGS84 " << lowerRightWGS84);

      // the iterator constructor can also be used to construct from arrays:
      const double Longitude[] = {upperLeftWGS84[0],upperRightWGS84[0],lowerLeftWGS84[0],lowerRightWGS84[0]};
      const double Latitude[] = {upperLeftWGS84[1],upperRightWGS84[1],lowerLeftWGS84[1],lowerRightWGS84[1]};

      std::vector<double> vecLong (Longitude, Longitude + sizeof(Longitude) / sizeof(double) );
      std::vector<double> vecLat (Latitude, Latitude + sizeof(Latitude) / sizeof(double) );

      std::vector<double> absVecLong;
      absVecLong.resize(vecLong.size());                         // allocate space

      std::vector<double> absVecLat;
      absVecLat.resize(vecLat.size());                         // allocate space

      std::vector<double>::iterator AbsLongit=absVecLong.begin();

      for (std::vector<double>::const_iterator it=vecLong.begin();it!=vecLong.end();++it)
        {
        *AbsLongit = vcl_abs(*it);
        ++AbsLongit;
        }

      std::vector<double>::iterator AbsLatit=absVecLat.begin();

      for (std::vector<double>::const_iterator it=vecLat.begin();it!=vecLat.end();++it)
        {
        *AbsLatit = vcl_abs(*it);
        ++AbsLatit;
        }

      const unsigned int distMinLong =
                         std::distance(absVecLong.begin(), min_element (absVecLong.begin(),absVecLong.end()));
      const unsigned int distMaxLong =
                         std::distance(absVecLong.begin(), max_element (absVecLong.begin(),absVecLong.end()));

      const unsigned int distMinLat =
                         std::distance(absVecLat.begin(), min_element (absVecLat.begin(),absVecLat.end()));
      const unsigned int distMaxLat =
                         std::distance(absVecLat.begin(), max_element (absVecLat.begin(),absVecLat.end()));

      //find corresponding tiled  for initialization
      //FIXME recode this properly

      int floorMinLong = 0;
      int floorMaxLong = 0;
      int floorMinLat = 0;
      int floorMaxLat = 0;

      if (vecLong.at(distMinLong) <= vecLong.at(distMaxLong))
        {
        floorMinLong = std::floor(vecLong.at(distMinLong));
        floorMaxLong = std::floor(vecLong.at(distMaxLong));
        }
      else
        {
        floorMinLong = std::floor(vecLong.at(distMaxLong));
        floorMaxLong = std::floor(vecLong.at(distMinLong));
        }

      if (vecLat.at(distMinLat) <= vecLat.at(distMaxLat))
        {
        floorMinLat = std::floor(vecLat.at(distMinLat));
        floorMaxLat = std::floor(vecLat.at(distMaxLat));
        }
      else
        {
        floorMinLat = std::floor(vecLat.at(distMaxLat));
        floorMaxLat = std::floor(vecLat.at(distMinLat));
        }

      std::vector<std::string> tiles;

      //Construct SRTM tile filename based on min/max lat/long
      for (int i = floorMinLat; i <= floorMaxLat;++i)
        {
        for (int j = floorMinLong; j <= floorMaxLong;++j)
          {
          std::ostringstream ossOutput;
          if (i < 0)
            {
            ossOutput << "S";
            }
          else
            {
            ossOutput << "N";
            }

          if (vcl_abs(i) <= 9)
            {
            ossOutput << "0";
            }
          ossOutput << vcl_abs(i);

          if (j < 0)
            {
            ossOutput << "W";
            }
          else
            {
            ossOutput << "E";
            }
          if (vcl_abs(j) >= 10 && vcl_abs(j) < 100)
            {
            ossOutput << "0";
            }
          else if (vcl_abs(j) <= 9)
            {
            ossOutput << "00";
            }

          ossOutput << vcl_abs(j);

          tiles.push_back(ossOutput.str());
          }
        }

      const std::string SRTMServerPath = "http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/";

      const char* args[] = {"Africa",
                            "Australia",
                            "Eurasia",
                            "Islands",
                            "North_America",
                            "South_America"};

      const std::vector<std::string> continent(args, args + sizeof(args)/sizeof(args[0]));

      const std::string extension = ".hgt.zip";
      const std::string extensionSimulation = ".hgt";

      //iterate over all tiles to build URLs
      for(std::vector<std::string>::const_iterator it= tiles.begin();it!=tiles.end();++it)
        {
        switch ( GetParameterInt("mode") )
          {
          case Mode_Download:
          {
          //Build URL
          bool findURL = false;
          std::string url;
          for(std::vector<std::string>::const_iterator contIt= continent.begin();contIt!=continent.end();++contIt)
            {
            std::ostringstream urlStream;
            CurlHelper::Pointer curl = CurlHelper::New();
            curl->SetTimeout(0);
            urlStream << SRTMServerPath;
            urlStream << *contIt;
            urlStream << "/";
            urlStream << *it;
            urlStream << extension;

            url = urlStream.str();

            if (!curl->IsCurlReturnHttpError( urlStream.str()))
              {
              findURL = true;
              break;
              }
            }

          if (!findURL)
            {
            itkExceptionMacro(<< url  <<" not found!");
            }

          otbAppLogINFO(<< "Found Tile on USGS server at URL: " << url);
          // TODO use the RetrieveUrlInMemory? In this case need to adapt the timeout
          CurlHelper::Pointer curlReq = CurlHelper::New();
          curlReq->SetTimeout(0);
          curlReq->RetrieveFile(url, GetParameterString("mode.download.outdir") + "/" + *it + extension);
          //TODO unzip here (can do this in memory?)
          }
          break;
          case Mode_Simulate:
          {
          simulateTilesVector.push_back(*it + extensionSimulation);
          }
          break;
          }
        }
      }
    switch ( GetParameterInt("mode") )
      {
      case Mode_Simulate:
      {
      std::ostringstream listStream;
      listStream << "Corresponding SRTM tiles: ";
      for(std::vector<std::string>::const_iterator it= simulateTilesVector.begin();it!=simulateTilesVector.end();++it)
        {
        listStream << *it << " ";
        }
      otbAppLogINFO( << listStream.str());
      }
      break;
      }
  }
};

}
}

OTB_APPLICATION_EXPORT(otb::Wrapper::DownloadSRTMTiles)
<commit_msg>STYLE<commit_after>/*=========================================================================

 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notices for more information.

 =========================================================================*/
#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"
#include "otbGenericRSTransform.h"

namespace otb
{

enum
{
  Mode_Download,
  Mode_Simulate
};

namespace Wrapper
{

class DownloadSRTMTiles : public Application
{
public:
  /** Standard class typedefs. */
  typedef DownloadSRTMTiles             Self;
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  typedef otb::GenericRSTransform<>     RSTransformType;

  typedef FloatVectorImageType::IndexType IndexType;
  typedef FloatVectorImageType::PointType PointType;
  typedef FloatVectorImageType::SizeType  SizeType;
  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(DownloadSRTMTiles, otb::Application);

private:

  void DoInit()
  {
    SetName("DownloadSRTMTiles");
    SetDescription("Download or list SRTM tiles related to images");

    // Documentation
    SetDocName("Download or list SRTM tiles related to images");
    SetDocLongDescription("Download or list SRTM tiles related to images...");
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(" ");

    AddDocTag("Utilities");
    AddDocTag(Tags::Manip);

    AddParameter(ParameterType_InputImageList,  "il",   "Input images list");
    SetParameterDescription("il", "The list of images on which you want to determine corresponding SRTM tiles.");

    // UserDefined values
    AddParameter(ParameterType_Choice, "mode", "download or simulate");
    MandatoryOn("mode");

    AddChoice("mode.download", "Download");
    SetParameterDescription("mode.download","Download.");

    AddParameter(ParameterType_OutputFilename, "mode.download.outdir", "ouput dir");
    SetParameterDescription("mode.download.outdir", "out dir");

    AddChoice("mode.simulate", "List tiles");
    SetParameterDescription("mode.simulate","List tiles");

    // Doc example parameter settings
    SetDocExampleParameterValue("il", "QB_Toulouse_Ortho_XS.tif");
    SetDocExampleParameterValue("mode", "simulate");
  }

  void DoUpdateParameters()
  {
    // Nothing to do here : all parameters are independent
  }

  void DoExecute()
  {
    // Get the input image list
    FloatVectorImageListType::Pointer inList = this->GetParameterImageList("il");

    if( inList->Size() == 0 )
      {
      itkExceptionMacro("No input Image set...");
      }

    inList->GetNthElement(0)->UpdateOutputInformation();

    std::vector<std::string> simulateTilesVector;

    for( unsigned int i=0; i<inList->Size(); i++ )
      {
      FloatVectorImageType::Pointer inImage = inList->GetNthElement(i);
      inImage->UpdateOutputInformation();

      RSTransformType::Pointer rsTransformToWGS84 = RSTransformType::New();
      rsTransformToWGS84->SetInputKeywordList(inImage->GetImageKeywordlist());
      rsTransformToWGS84->SetInputProjectionRef(inImage->GetProjectionRef());

      rsTransformToWGS84->InstanciateTransform();

      const SizeType size = inImage->GetLargestPossibleRegion().GetSize();

      PointType upperLeft;
      upperLeft[0] = 0;
      upperLeft[1] = 0;
      PointType upperLeftWGS84 = rsTransformToWGS84->TransformPoint(upperLeft);
      otbAppLogINFO(<< "upperLeftWGS84 " << upperLeftWGS84);

      PointType upperRight;
      upperRight[0] = size[0] - 1;
      upperRight[1] = 0;
      PointType upperRightWGS84 = rsTransformToWGS84->TransformPoint(upperRight);
      otbAppLogINFO(<< "upperRightWGS84 " << upperRightWGS84);

      PointType lowerLeft;
      lowerLeft[0] = 0;
      lowerLeft[1] = size[1] - 1;
      PointType lowerLeftWGS84 = rsTransformToWGS84->TransformPoint(lowerLeft);
      otbAppLogINFO(<< "lowerLeftWGS84 " << lowerLeftWGS84);

      PointType lowerRight;
      lowerRight[0] = size[0] - 1;
      lowerRight[1] = size[1] - 1;
      PointType lowerRightWGS84 = rsTransformToWGS84->TransformPoint(lowerRight);
      otbAppLogINFO(<< "lowerRightWGS84 " << lowerRightWGS84);

      // the iterator constructor can also be used to construct from arrays:
      const double Longitude[] = {upperLeftWGS84[0],upperRightWGS84[0],lowerLeftWGS84[0],lowerRightWGS84[0]};
      const double Latitude[] = {upperLeftWGS84[1],upperRightWGS84[1],lowerLeftWGS84[1],lowerRightWGS84[1]};

      std::vector<double> vecLong (Longitude, Longitude + sizeof(Longitude) / sizeof(double) );
      std::vector<double> vecLat (Latitude, Latitude + sizeof(Latitude) / sizeof(double) );

      std::vector<double> absVecLong;
      absVecLong.resize(vecLong.size());                         // allocate space

      std::vector<double> absVecLat;
      absVecLat.resize(vecLat.size());                         // allocate space

      std::vector<double>::iterator AbsLongit=absVecLong.begin();

      for (std::vector<double>::const_iterator it=vecLong.begin(); it!=vecLong.end(); ++it)
        {
        *AbsLongit = vcl_abs(*it);
        ++AbsLongit;
        }

      std::vector<double>::iterator AbsLatit=absVecLat.begin();

      for (std::vector<double>::const_iterator it=vecLat.begin(); it!=vecLat.end(); ++it)
        {
        *AbsLatit = vcl_abs(*it);
        ++AbsLatit;
        }

      const unsigned int distMinLong =
                         std::distance(absVecLong.begin(), min_element (absVecLong.begin(),absVecLong.end()));
      const unsigned int distMaxLong =
                         std::distance(absVecLong.begin(), max_element (absVecLong.begin(),absVecLong.end()));

      const unsigned int distMinLat =
                         std::distance(absVecLat.begin(), min_element (absVecLat.begin(),absVecLat.end()));
      const unsigned int distMaxLat =
                         std::distance(absVecLat.begin(), max_element (absVecLat.begin(),absVecLat.end()));

      //find corresponding tiled  for initialization
      //FIXME recode this properly

      int floorMinLong = 0;
      int floorMaxLong = 0;
      int floorMinLat = 0;
      int floorMaxLat = 0;

      if (vecLong.at(distMinLong) <= vecLong.at(distMaxLong))
        {
        floorMinLong = std::floor(vecLong.at(distMinLong));
        floorMaxLong = std::floor(vecLong.at(distMaxLong));
        }
      else
        {
        floorMinLong = std::floor(vecLong.at(distMaxLong));
        floorMaxLong = std::floor(vecLong.at(distMinLong));
        }

      if (vecLat.at(distMinLat) <= vecLat.at(distMaxLat))
        {
        floorMinLat = std::floor(vecLat.at(distMinLat));
        floorMaxLat = std::floor(vecLat.at(distMaxLat));
        }
      else
        {
        floorMinLat = std::floor(vecLat.at(distMaxLat));
        floorMaxLat = std::floor(vecLat.at(distMinLat));
        }

      std::vector<std::string> tiles;

      //Construct SRTM tile filename based on min/max lat/long
      for (int i = floorMinLat; i <= floorMaxLat; ++i)
        {
        for (int j = floorMinLong; j <= floorMaxLong; ++j)
          {
          std::ostringstream ossOutput;
          if (i < 0)
            {
            ossOutput << "S";
            }
          else
            {
            ossOutput << "N";
            }

          if (vcl_abs(i) <= 9)
            {
            ossOutput << "0";
            }
          ossOutput << vcl_abs(i);

          if (j < 0)
            {
            ossOutput << "W";
            }
          else
            {
            ossOutput << "E";
            }
          if (vcl_abs(j) >= 10 && vcl_abs(j) < 100)
            {
            ossOutput << "0";
            }
          else if (vcl_abs(j) <= 9)
            {
            ossOutput << "00";
            }

          ossOutput << vcl_abs(j);

          tiles.push_back(ossOutput.str());
          }
        }

      const std::string SRTMServerPath = "http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/";

      const char* args[] = {"Africa",
                            "Australia",
                            "Eurasia",
                            "Islands",
                            "North_America",
                            "South_America"};

      const std::vector<std::string> continent(args, args + sizeof(args)/sizeof(args[0]));

      const std::string extension = ".hgt.zip";
      const std::string extensionSimulation = ".hgt";

      //iterate over all tiles to build URLs
      for(std::vector<std::string>::const_iterator it= tiles.begin(); it!=tiles.end(); ++it)
        {
        switch ( GetParameterInt("mode") )
          {
          case Mode_Download:
          {
          //Build URL
          bool findURL = false;
          std::string url;
          for(std::vector<std::string>::const_iterator contIt= continent.begin(); contIt!=continent.end(); ++contIt)
            {
            std::ostringstream urlStream;
            CurlHelper::Pointer curl = CurlHelper::New();
            curl->SetTimeout(0);
            urlStream << SRTMServerPath;
            urlStream << *contIt;
            urlStream << "/";
            urlStream << *it;
            urlStream << extension;

            url = urlStream.str();

            if (!curl->IsCurlReturnHttpError( urlStream.str()))
              {
              findURL = true;
              break;
              }
            }

          if (!findURL)
            {
            itkExceptionMacro(<< url  <<" not found!");
            }

          otbAppLogINFO(<< "Found Tile on USGS server at URL: " << url);
          // TODO use the RetrieveUrlInMemory? In this case need to adapt the timeout
          CurlHelper::Pointer curlReq = CurlHelper::New();
          curlReq->SetTimeout(0);
          curlReq->RetrieveFile(url, GetParameterString("mode.download.outdir") + "/" + *it + extension);
          //TODO unzip here (can do this in memory?)
          }
          break;
          case Mode_Simulate:
          {
          simulateTilesVector.push_back(*it + extensionSimulation);
          }
          break;
          }
        }
      }
    switch ( GetParameterInt("mode") )
      {
      case Mode_Simulate:
      {
      std::ostringstream listStream;
      listStream << "Corresponding SRTM tiles: ";
      for(std::vector<std::string>::const_iterator it= simulateTilesVector.begin(); it!=simulateTilesVector.end(); ++it)
        {
        listStream << *it << " ";
        }
      otbAppLogINFO( << listStream.str());
      }
      break;
      }
  }
};

}
}

OTB_APPLICATION_EXPORT(otb::Wrapper::DownloadSRTMTiles)
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
//
// 	Permission is hereby granted, free of charge, to any person obtaining a copy
// 	of this software and associated documentation files (the "Software"), to deal
// 	in the Software without restriction, including without limitation the rights
// 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// 	copies of the Software, and to permit persons to whom the Software is
// 	furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
// 	all copies or substantial portions of the Software.
//
// 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// 	THE SOFTWARE.

#include "Tests.h"
#include <UnitTest++.h>
#include <MTScheduler.h>

SUITE(StackSizeTests)
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct StandartStackSizeTask
{
	MT_DECLARE_TASK(StandartStackSizeTask, MT::StackRequirements::STANDARD, MT::Color::Blue);

	void Do(MT::FiberContext&)
	{
		byte stackData[26000];
		memset(stackData, 0x0D, MT_ARRAY_SIZE(stackData));
	}
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct ExtendedStackSizeTask
{
	MT_DECLARE_TASK(ExtendedStackSizeTask, MT::StackRequirements::EXTENDED, MT::Color::Red);

	void Do(MT::FiberContext&)
	{
		byte stackData[262144];
		memset(stackData, 0x0D, MT_ARRAY_SIZE(stackData));
	}

};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(RunStandartTasks)
{
	MT::TaskScheduler scheduler;

	StandartStackSizeTask tasks[100];
	scheduler.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
	CHECK(scheduler.WaitAll(1000));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(RunExtendedTasks)
{
	MT::TaskScheduler scheduler;

	ExtendedStackSizeTask tasks[100];
	scheduler.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
	CHECK(scheduler.WaitAll(1000));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(RunMixedTasks)
{
	MT::TaskScheduler scheduler;

	MT::TaskPool<ExtendedStackSizeTask, 64> extendedTaskPool;
	MT::TaskPool<StandartStackSizeTask, 64> standardTaskPool;

	MT::TaskHandle taskHandles[100];
	for (size_t i = 0; i < MT_ARRAY_SIZE(taskHandles); ++i)
	{
		MT::TaskHandle handle;

		if (i & 1)
		{
			handle = extendedTaskPool.Alloc(ExtendedStackSizeTask());
		} else
		{
			handle = standardTaskPool.Alloc(StandartStackSizeTask());
		}
		taskHandles[i] = handle;
	}

	scheduler.RunAsync(MT::TaskGroup::Default(), &taskHandles[0], MT_ARRAY_SIZE(taskHandles));
	CHECK(scheduler.WaitAll(1000));
}

}
<commit_msg>Change stack size in stack size test.<commit_after>// The MIT License (MIT)
//
// 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
//
// 	Permission is hereby granted, free of charge, to any person obtaining a copy
// 	of this software and associated documentation files (the "Software"), to deal
// 	in the Software without restriction, including without limitation the rights
// 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// 	copies of the Software, and to permit persons to whom the Software is
// 	furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
// 	all copies or substantial portions of the Software.
//
// 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// 	THE SOFTWARE.

#include "Tests.h"
#include <UnitTest++.h>
#include <MTScheduler.h>

SUITE(StackSizeTests)
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct StandartStackSizeTask
{
	MT_DECLARE_TASK(StandartStackSizeTask, MT::StackRequirements::STANDARD, MT::Color::Blue);

	void Do(MT::FiberContext&)
	{
		byte stackData[20000];
		memset(stackData, 0x0D, MT_ARRAY_SIZE(stackData));
	}
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct ExtendedStackSizeTask
{
	MT_DECLARE_TASK(ExtendedStackSizeTask, MT::StackRequirements::EXTENDED, MT::Color::Red);

	void Do(MT::FiberContext&)
	{
		byte stackData[262144];
		memset(stackData, 0x0D, MT_ARRAY_SIZE(stackData));
	}

};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(RunStandartTasks)
{
	MT::TaskScheduler scheduler;

	StandartStackSizeTask tasks[100];
	scheduler.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
	CHECK(scheduler.WaitAll(1000));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(RunExtendedTasks)
{
	MT::TaskScheduler scheduler;

	ExtendedStackSizeTask tasks[100];
	scheduler.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
	CHECK(scheduler.WaitAll(1000));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(RunMixedTasks)
{
	MT::TaskScheduler scheduler;

	MT::TaskPool<ExtendedStackSizeTask, 64> extendedTaskPool;
	MT::TaskPool<StandartStackSizeTask, 64> standardTaskPool;

	MT::TaskHandle taskHandles[100];
	for (size_t i = 0; i < MT_ARRAY_SIZE(taskHandles); ++i)
	{
		MT::TaskHandle handle;

		if (i & 1)
		{
			handle = extendedTaskPool.Alloc(ExtendedStackSizeTask());
		} else
		{
			handle = standardTaskPool.Alloc(StandartStackSizeTask());
		}
		taskHandles[i] = handle;
	}

	scheduler.RunAsync(MT::TaskGroup::Default(), &taskHandles[0], MT_ARRAY_SIZE(taskHandles));
	CHECK(scheduler.WaitAll(1000));
}

}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "GameManager.h"
#include "GameRoom.h"
#include "Game.h"
#include "Player.h"
#include "Unit.h"
#include "ClientManager.h"
#include "ClientSession.h"
#include "ContactListener.h"
#include "Scheduler.h"
#include "Config.h"

GameManager* GGameManager = nullptr;

///////////////////////////////////////////////////////////////////////////
/*
    GameRoom 관련
*/
///////////////////////////////////////////////////////////////////////////
GameRoom* GameManager::CreateRoom()
{
    if (m_MakeRoomNum == 0)
        LowTick();

    if (m_RoomList.find(m_MakeRoomNum) != m_RoomList.end())
    {
        DeleteRoom(m_MakeRoomNum);
    }
    GameRoom* room = new GameRoom(++m_MakeRoomNum);
    m_RoomList[m_MakeRoomNum] = room;
    return room;
}

void GameManager::DeleteRoom(int roomId)
{
    if (roomId < 0)
    {
        printf(" - DeleteRoom Failed ! : roomId is invalid \n");
        return;
    }
    auto room = m_RoomList.find(roomId);
    if (room == m_RoomList.end())
    {
        printf(" - DeleteRoom Failed ! : relevant room isn't \n");
        return;
    }
    delete room->second;
    m_RoomList.erase(room);
    printf(" - Destroy %d Room ! \n", roomId);
}

GameRoom* GameManager::SearchRoom(int roomId)
{
    if (roomId < 0)
    {
        printf(" - SearchRoom Failed ! : roomId is invalid \n");
        return nullptr;
    }
    auto room = m_RoomList.find(roomId);
    if (room == m_RoomList.end())
    {
        printf(" - SearchRoom Failed ! : relevant room isn't \n");
        return nullptr;
    }
    return room->second;
}

int GameManager::SearchEmptyRoom()
{
    for (auto& room : m_RoomList)
    {
        if (room.second->IsJoinAble())
        {
            return room.second->GetRoomID();
        }
    }
    printf(" - No Room ! \n");
    return -1;
}

void GameManager::JoinRoom(int roomId, Player* player)
{
    if (roomId < 0 || player == nullptr)
    {
        printf(" - JoinRoom Failed ! : invalid info \n");
        return;
    }
    m_RoomList[roomId]->JoinPlayer(player);
}

void GameManager::OutPlayer(int roomId, int playerId)
{
    if (roomId < 0 || playerId < 0)
    {
        printf(" - OutPlayer Failed ! : invalid ID \n");
        return;
    }
    auto game = m_GameList.find(roomId);
    if (game != m_GameList.end())
    {
        game->second->OutPlayer(playerId);
        if (game->second->GetPlayerList().size() == 0)
        {
            DeleteGame(roomId);
        }
    }
    auto room = m_RoomList.find(roomId);
    if (room != m_RoomList.end())
    {
        room->second->OutPlayer(playerId);
        if (room->second->GetPlayerList().size() == 0)
        {
            DeleteRoom(roomId);
        }
    }
}

///////////////////////////////////////////////////////////////////////////
/*
    Game 관련
*/
///////////////////////////////////////////////////////////////////////////
Game* GameManager::SearchGame(int gameId)
{
    if (gameId < 0)
    {
        printf(" - SearchGame Failed ! : gameId is invalid \n");
        return nullptr;
    }
    auto game = m_GameList.find(gameId);
    if (game == m_GameList.end())
    {
        printf(" - SearchGame Failed ! : relevant game isn't \n");
        return nullptr;
    }
    return game->second;
}

void GameManager::CreateGame(int gameId)
{
    if (gameId < 0)
    {
        printf(" - CreateGame Failed ! : gameId is invalid \n");
        return;
    }
    auto room = m_RoomList.find(gameId);
    if (room == m_RoomList.end())
    {
        printf(" - CreateGame Failed ! : room info is invalid \n");
        return;
    }
    if (m_GameList.find(gameId) != m_GameList.end())
    {
        DeleteGame(gameId);
    }
    Game* game = new Game(room->second);
    DeleteRoom(gameId);
    m_GameList[gameId] = game;
    game->InitGame();
}

void GameManager::DeleteGame(int gameId)
{
    if (gameId < 0)
    {
        printf(" - DeleteGame Failed ! : gameId is invalid \n");
        return;
    }
    auto game = m_GameList.find(gameId);
    if (game == m_GameList.end())
    {
        printf(" - DeleteGame Failed ! : relevant game isn't \n");
        return;
    }
    delete game->second;
    m_GameList.erase(game);
    printf(" - Destroy %d Game ! \n", gameId);
}

///////////////////////////////////////////////////////////////////////////
/*
    Player 관련
*/
///////////////////////////////////////////////////////////////////////////
Player* GameManager::SearchPlayer(int playerId)
{
    if (playerId < 0)
    {
        printf(" - SearchPlayer Failed ! : playerId is invalid \n");
        return nullptr;
    }
    for (auto& game : m_GameList)
    {
        for (auto& player : game.second->GetPlayerList())
        {
            if (player.first == playerId)
            {
                return player.second;
            }
        }
    }
    printf(" - SearchPlayer Failed ! : relevant player isn't \n");
    return nullptr;
}

void GameManager::PlayerOut(int playerId)
{
    if (playerId < 0)
    {
        printf(" - PlayerOut Failed ! : playerId is invalid \n");
        return;
    }
    auto player = SearchPlayer(playerId);
    if (player == nullptr)
    {
        printf(" - PlayerOut Failed ! : relevant player isn't \n");
        return;
    }
    OutPlayer(player->GetRoomID(), playerId);
}

///////////////////////////////////////////////////////////////////////////
/*
    매 프레임마다 실행
*/
///////////////////////////////////////////////////////////////////////////
void GameManager::Tick(float dt)
{
    m_World->Step(dt, 8, 3);

    for (auto& room : m_RoomList)
    {
        if (room.second->IsAllReady())
        {
            // 게임 구동 시작!;
            printf(" - All Player is Ready ! :: %d Room is Game Start !! \n", room.first);

            CallFuncAfter(MANAGER_UPDATE_INTERVAL, this, &GameManager::CreateGame, room.first);
            room.second->SetIsGameExist(true);

            room.second->InitReady();
        }
    }

    for (auto& game : m_GameList)
    {
		if (game.second != NULL && game.second->IsEnd())
		{
			continue;
		}

        for (auto& player : game.second->GetPlayerList())
        {
            auto client = GClientManager->GetClient(player.first);
            if (client == nullptr)
            {
                PlayerOut(player.first);
                continue;
            }

            if (client->GetPlayer()->GetMyHero()->GetUnitHp() <= 0)
            {
				client->GameOverCast(client->GetPlayer()->GetPlayerID());
                game.second->EndGame();
                DeleteGame(game.second->GetGameID());
                break;
            }

            if (game.second->IsReady())
            {
                CallFuncAfter(MANAGER_UPDATE_INTERVAL, client, &ClientSession::ServerRunComplete);
                game.second->SetIsReady(false);
            }

            if (!game.second->IsStart() && game.second->GetLoadedPlayerNum() >= 2)
            {
                client->StartGame();
                game.second->SetIsStart(true);
            }

            if (!game.second->IsStart())
                continue;

            for (auto& unit : player.second->GetUnitList())
            {
                unit.second->Movement();
            }
        }
    }
}

///////////////////////////////////////////////////////////////////////////
/*
    낮은 주기로 반복 실행
*/
///////////////////////////////////////////////////////////////////////////
void GameManager::LowTick()
{
    int i = 0, j = 0;
    for (b2Body* b = m_World->GetBodyList(); b; b = b->GetNext())
    {
        if (!b->IsAwake())
        {
            auto unit = static_cast<Unit*>(b->GetUserData());
            unit->Crashing(false);
            ++j;
        }
        ++i;
    }
    printf(" - Total Sleeping Body Num [%2d/%2d] \n", j, i);
    CallFuncAfter(MANAGER_UPDATE_INTERVAL*3, this, &GameManager::LowTick);
}

///////////////////////////////////////////////////////////////////////////
/*
    데미지 계산 함수들
*/
///////////////////////////////////////////////////////////////////////////
bool GameManager::ApplyDamage(Unit* unitA, Unit* unitB)
{
    if (unitA->GetPlayerID() == unitB->GetPlayerID())
    {
        return false;
    }
    else
    {
        return true;
    }
}

void GameManager::ExchangeDamage(Unit* unitA, Unit* unitB)
{
    int damageA = unitA->GetUnitDamage();
    int damageB = unitB->GetUnitDamage();
    int unitAHp = unitA->GetUnitHp() - damageB;
    int unitBHp = unitB->GetUnitHp() - damageA;

    unitA->SetUnitHp(unitAHp);
    unitB->SetUnitHp(unitBHp);

    int AplayerId = unitA->GetPlayerID();
    int BplayerId = unitB->GetPlayerID();

    GClientManager->GetClient(AplayerId)->HpBroadCast(AplayerId, unitA->GetUnitID(), unitAHp);
    GClientManager->GetClient(BplayerId)->HpBroadCast(BplayerId, unitB->GetUnitID(), unitBHp);
}

///////////////////////////////////////////////////////////////////////////
/*
    물리세계 구축
*/
///////////////////////////////////////////////////////////////////////////
void GameManager::InitPhyWorld()
{
    b2Vec2 gravity(0.0f, 0.0f);
    m_World = new b2World(gravity);

    m_World->SetAllowSleeping(true);
    m_World->SetContinuousPhysics(true);

    m_Contact = new ContactListener();
    m_World->SetContactListener((b2ContactListener*)m_Contact);
}

void GameManager::DeletePhyWorld()
{
    delete m_World;
    delete m_Contact;
}
<commit_msg>[S]일단 커밋<commit_after>#include "stdafx.h"
#include "GameManager.h"
#include "GameRoom.h"
#include "Game.h"
#include "Player.h"
#include "Unit.h"
#include "ClientManager.h"
#include "ClientSession.h"
#include "ContactListener.h"
#include "Scheduler.h"
#include "Config.h"

GameManager* GGameManager = nullptr;

///////////////////////////////////////////////////////////////////////////
/*
    GameRoom 관련
*/
///////////////////////////////////////////////////////////////////////////
GameRoom* GameManager::CreateRoom()
{
    if (m_MakeRoomNum == 0)
        LowTick();

    if (m_RoomList.find(m_MakeRoomNum) != m_RoomList.end())
    {
        DeleteRoom(m_MakeRoomNum);
    }
    GameRoom* room = new GameRoom(++m_MakeRoomNum);
    m_RoomList[m_MakeRoomNum] = room;
    return room;
}

void GameManager::DeleteRoom(int roomId)
{
    if (roomId < 0)
    {
        printf(" - DeleteRoom Failed ! : roomId is invalid \n");
        return;
    }
    auto room = m_RoomList.find(roomId);
    if (room == m_RoomList.end())
    {
        printf(" - DeleteRoom Failed ! : relevant room isn't \n");
        return;
    }
    delete room->second;
    m_RoomList.erase(room);
    printf(" - Destroy %d Room ! \n", roomId);
}

GameRoom* GameManager::SearchRoom(int roomId)
{
    if (roomId < 0)
    {
        printf(" - SearchRoom Failed ! : roomId is invalid \n");
        return nullptr;
    }
    auto room = m_RoomList.find(roomId);
    if (room == m_RoomList.end())
    {
        printf(" - SearchRoom Failed ! : relevant room isn't \n");
        return nullptr;
    }
    return room->second;
}

int GameManager::SearchEmptyRoom()
{
    for (auto& room : m_RoomList)
    {
        if (room.second->IsJoinAble())
        {
            return room.second->GetRoomID();
        }
    }
    printf(" - No Room ! \n");
    return -1;
}

void GameManager::JoinRoom(int roomId, Player* player)
{
    if (roomId < 0 || player == nullptr)
    {
        printf(" - JoinRoom Failed ! : invalid info \n");
        return;
    }
    m_RoomList[roomId]->JoinPlayer(player);
}

void GameManager::OutPlayer(int roomId, int playerId)
{
    if (roomId < 0 || playerId < 0)
    {
        printf(" - OutPlayer Failed ! : invalid ID \n");
        return;
    }
    auto game = m_GameList.find(roomId);
    if (game != m_GameList.end())
    {
        game->second->OutPlayer(playerId);
        if (game->second->GetPlayerList().size() == 0)
        {
            DeleteGame(roomId);
        }
    }
    auto room = m_RoomList.find(roomId);
    if (room != m_RoomList.end())
    {
        room->second->OutPlayer(playerId);
        if (room->second->GetPlayerList().size() == 0)
        {
            DeleteRoom(roomId);
        }
    }
}

///////////////////////////////////////////////////////////////////////////
/*
    Game 관련
*/
///////////////////////////////////////////////////////////////////////////
Game* GameManager::SearchGame(int gameId)
{
    if (gameId < 0)
    {
        printf(" - SearchGame Failed ! : gameId is invalid \n");
        return nullptr;
    }
    auto game = m_GameList.find(gameId);
    if (game == m_GameList.end())
    {
        printf(" - SearchGame Failed ! : relevant game isn't \n");
        return nullptr;
    }
    return game->second;
}

void GameManager::CreateGame(int gameId)
{
    if (gameId < 0)
    {
        printf(" - CreateGame Failed ! : gameId is invalid \n");
        return;
    }
    auto room = m_RoomList.find(gameId);
    if (room == m_RoomList.end())
    {
        printf(" - CreateGame Failed ! : room info is invalid \n");
        return;
    }
    if (m_GameList.find(gameId) != m_GameList.end())
    {
        DeleteGame(gameId);
    }
    Game* game = new Game(room->second);
    DeleteRoom(gameId);
    m_GameList[gameId] = game;
    game->InitGame();
}

void GameManager::DeleteGame(int gameId)
{
    if (gameId < 0)
    {
        printf(" - DeleteGame Failed ! : gameId is invalid \n");
        return;
    }
    auto game = m_GameList.find(gameId);
    if (game == m_GameList.end())
    {
        printf(" - DeleteGame Failed ! : relevant game isn't \n");
        return;
    }
    delete game->second;
    m_GameList.erase(game);
    printf(" - Destroy %d Game ! \n", gameId);
}

///////////////////////////////////////////////////////////////////////////
/*
    Player 관련
*/
///////////////////////////////////////////////////////////////////////////
Player* GameManager::SearchPlayer(int playerId)
{
    if (playerId < 0)
    {
        printf(" - SearchPlayer Failed ! : playerId is invalid \n");
        return nullptr;
    }
    for (auto& game : m_GameList)
    {
        for (auto& player : game.second->GetPlayerList())
        {
            if (player.first == playerId)
            {
                return player.second;
            }
        }
    }
    printf(" - SearchPlayer Failed ! : relevant player isn't \n");
    return nullptr;
}

void GameManager::PlayerOut(int playerId)
{
    if (playerId < 0)
    {
        printf(" - PlayerOut Failed ! : playerId is invalid \n");
        return;
    }
    auto player = SearchPlayer(playerId);
    if (player == nullptr)
    {
        printf(" - PlayerOut Failed ! : relevant player isn't \n");
        return;
    }
    OutPlayer(player->GetRoomID(), playerId);
}

///////////////////////////////////////////////////////////////////////////
/*
    매 프레임마다 실행
*/
///////////////////////////////////////////////////////////////////////////
void GameManager::Tick(float dt)
{
    m_World->Step(dt, 8, 3);

    for (auto& room : m_RoomList)
    {
        if (room.second->IsAllReady())
        {
            // 게임 구동 시작!;
            printf(" - All Player is Ready ! :: %d Room is Game Start !! \n", room.first);

            CallFuncAfter(MANAGER_UPDATE_INTERVAL, this, &GameManager::CreateGame, room.first);
            room.second->SetIsGameExist(true);

            room.second->InitReady();
        }
    }

    for (auto& game : m_GameList)
    {
		if (game.second != NULL || game.second->IsEnd())
		{
			continue;
		}

        for (auto& player : game.second->GetPlayerList())
        {
            auto client = GClientManager->GetClient(player.first);
            if (client == nullptr)
            {
                PlayerOut(player.first);
                continue;
            }

            if (client->GetPlayer()->GetMyHero()->GetUnitHp() <= 0)
            {
				client->GameOverCast(client->GetPlayer()->GetPlayerID());
                game.second->EndGame();
                //DeleteGame(game.second->GetGameID());
                break;
            }

            if (game.second->IsReady())
            {
                CallFuncAfter(MANAGER_UPDATE_INTERVAL, client, &ClientSession::ServerRunComplete);
                game.second->SetIsReady(false);
            }

            if (!game.second->IsStart() && game.second->GetLoadedPlayerNum() >= 2)
            {
                client->StartGame();
                game.second->SetIsStart(true);
            }

            if (!game.second->IsStart())
                continue;

            for (auto& unit : player.second->GetUnitList())
            {
                unit.second->Movement();
            }
        }
    }
}

///////////////////////////////////////////////////////////////////////////
/*
    낮은 주기로 반복 실행
*/
///////////////////////////////////////////////////////////////////////////
void GameManager::LowTick()
{
    int i = 0, j = 0;
    for (b2Body* b = m_World->GetBodyList(); b; b = b->GetNext())
    {
        if (!b->IsAwake())
        {
            auto unit = static_cast<Unit*>(b->GetUserData());
            unit->Crashing(false);
            ++j;
        }
        ++i;
    }
    printf(" - Total Sleeping Body Num [%2d/%2d] \n", j, i);
    CallFuncAfter(MANAGER_UPDATE_INTERVAL*3, this, &GameManager::LowTick);
}

///////////////////////////////////////////////////////////////////////////
/*
    데미지 계산 함수들
*/
///////////////////////////////////////////////////////////////////////////
bool GameManager::ApplyDamage(Unit* unitA, Unit* unitB)
{
    if (unitA->GetPlayerID() == unitB->GetPlayerID())
    {
        return false;
    }
    else
    {
        return true;
    }
}

void GameManager::ExchangeDamage(Unit* unitA, Unit* unitB)
{
    int damageA = unitA->GetUnitDamage();
    int damageB = unitB->GetUnitDamage();
    int unitAHp = unitA->GetUnitHp() - damageB;
    int unitBHp = unitB->GetUnitHp() - damageA;

    unitA->SetUnitHp(unitAHp);
    unitB->SetUnitHp(unitBHp);

    int AplayerId = unitA->GetPlayerID();
    int BplayerId = unitB->GetPlayerID();

    GClientManager->GetClient(AplayerId)->HpBroadCast(AplayerId, unitA->GetUnitID(), unitAHp);
    GClientManager->GetClient(BplayerId)->HpBroadCast(BplayerId, unitB->GetUnitID(), unitBHp);
}

///////////////////////////////////////////////////////////////////////////
/*
    물리세계 구축
*/
///////////////////////////////////////////////////////////////////////////
void GameManager::InitPhyWorld()
{
    b2Vec2 gravity(0.0f, 0.0f);
    m_World = new b2World(gravity);

    m_World->SetAllowSleeping(true);
    m_World->SetContinuousPhysics(true);

    m_Contact = new ContactListener();
    m_World->SetContactListener((b2ContactListener*)m_Contact);
}

void GameManager::DeletePhyWorld()
{
    delete m_World;
    delete m_Contact;
}
<|endoftext|>