<commit_before>// http://lgecodejam.com
// lge code jam August, 2014
// problem.3
// hyungyu.jang@lge.com

#if defined _EXTERNAL_DEBUGGER && defined _DEBUG
    #include <trace/trace.h>
#else
    #define trace printf
#endif

#include <cstdio>
#include <cstring>
#include <map>

using namespace std;
typedef map<int, int> MII;

int page, link, start, limit;
MII in[1002]; // index, count
int way[10001][1002];
const int DEVIDER [] = {
    1, 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29
};

void count(int from) {
    memset(way, 0, sizeof(int) * 10001 * 1002);
    int i;
    for (i = 1; i <= page; i++) {
        if (in[from][i]) way[1][i] = in[from][i];
    }

    for (i = 2; i <= limit; i++) {
        for (int index = 1; index <= page; index++) {
            int c = way[i-1][index];
            if (c == 0) continue;
            if (c % DEVIDER[from] == 0) continue;

            MII::iterator j = in[index].begin();
            for (; j != in[index].end(); j++) {
                int to = j->first;
                int cc = j->second;
                way[i][to] += (c * cc) % DEVIDER[from];
            }
            way[i][index] %= DEVIDER[from];
        }
    }

    int solution(0);
    for (i = 1; i <= limit; i++) {
        solution += way[i][1];
    }
    printf("%d ", solution % DEVIDER[from]);

}

void solve() {
    int i, from, to, solution(0);
    scanf("%d %d %d %d", &page, &link, &start, &limit);
    for (i = 0; i < link; i++) {
        scanf("%d %d", &from, &to);
        in[from][to]++;
    }

    start += 1;
    for (i = 2; i <= start; i++) {
        count(i);
    }
    printf("\n");
}

void clear() {
    for (int i = 1; i <= page; i++) {
        in[i].clear();
    }
}

int main(int, char*[]) {
    int num;
    scanf("%d", &num);
    for (int i = 0; i < num; i++) {solve(); clear();}
    return 0;
}
<commit_msg>lge code jam 2014 august problem 3 completed<commit_after>// http://lgecodejam.com
// lge code jam August, 2014
// problem.3
// hyungyu.jang@lge.com

#if defined _EXTERNAL_DEBUGGER && defined _DEBUG
    #include <trace/trace.h>
#else
    #define trace printf
#endif

#include <cstdio>
#include <cstring>
#include <map>

using namespace std;
typedef map<int, int> MII;
typedef long long int64;

const int64 DEVIDER [] = {
    1, 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
};
const int64 ALL = 2ll * 3ll * 5ll * 7ll * 11ll * 13ll * 17ll * 19ll * 23ll * 29ll;

int page, link, start, limit;
MII in[1002]; // index, count
int64 way[10001][1002];
int64 _length[12];

void count(int from) {
    memset(way, 0, sizeof(int64) * 10001 * 1002);
    int i;
    for (i = 1; i <= page; i++) {
        if (in[from][i]) way[1][i] = in[from][i];
    }

    for (i = 2; i <= limit; i++) {
        for (int index = 1; index <= page; index++) {
            int64 c = way[i-1][index];
            if (c == 0) continue;

            MII::iterator j = in[index].begin();
            for (; j != in[index].end(); j++) {
                int to = j->first;
                int64 cc = j->second;
                way[i][to] += (c *cc) % ALL;
            }
            //way[i][index] %= ALL;
        }
    }

    for (i = 1; i <= limit; i++) {
        for (int j = 2; j <= start; j++) {
            _length[j] += way[i][j] % DEVIDER[j];
        }
    }

    for (i = 2; i <= start; i++) {
        printf("%d ", _length[i] % DEVIDER[i]);
    }
    printf("\n");

}

void solve() {
    memset(_length, 0, sizeof(int64) * 12);
    int i, from, to, solution(0);
    scanf("%d %d %d %d", &page, &link, &start, &limit);
    for (i = 0; i < link; i++) {
        scanf("%d %d", &from, &to);
        in[to][from]++; // reverse
    }

    start++;
    count(1);
}

void clear() {
    for (int i = 1; i <= page; i++) {
        in[i].clear();
    }
}

int main(int, char*[]) {
    int num;
    scanf("%d", &num);
    for (int i = 0; i < num; i++) { solve(); clear(); }
    return 0;
}
<|endoftext|>


<commit_before>// Adobe Leaked Email Chcker
// Date: December 2013
// Author: Jervis Muindi

// Standard Lib Header
#include <iostream>

// Custom Common Code
#include "common/base/flags.h"
#include "common/base/init.h"

// Program Flags
DEFINE_string(db_path, "adobe.db",
	      "Path to LevelDB file containing leaked Adobe passwords."
	      "Defaults to using 'adobe.db'");

using namespace std;
int main(int argc, char**argv) {
  InitProgram(&argc, &argv);
  cout << "DB PathFlag is " << FLAGS_db_path;
  return 0;
}
<commit_msg>Add more program flags<commit_after>// Adobe Leaked Email Chcker
// Date: December 2013
// Author: Jervis Muindi

// Standard Lib Header
#include <iostream>

// Custom Common Code
#include "common/base/flags.h"
#include "common/base/init.h"
#include "common/log/log.h"

// Program Flags
DEFINE_string(file_path, "adobe.db",
	      "Path to LevelDB file containing leaked Adobe passwords."
	      "Defaults to using 'adobe.db'");
DEFINE_string(dump_file, "adobe_dump.txt",
	      "File path to the uncompressed raw dump of the adobe credentials.");
DEFINE_bool(process_raw_dump, false, "Assumes that the file path "
	    "in '--dump_file' points to a raw text dump of the credentials and process them"
	    "to generate an on disk LEVELDB hashtable with the name specified in '--output_file'."
            "The LEVELDB hastable will be queryable in O(1) / constant time. ");
using namespace std;

static void OutputFlags() {
  LOG(INFO) << "(LevelDB) file_path: " << FLAGS_file_path;
  LOG(INFO) << "dump_file: " << FLAGS_dump_file;
  LOG(INFO) << "process_raw_dump?" << FLAGS_process_raw_dump;
}

int main(int argc, char **argv) {
  InitProgram(&argc, &argv);
  OutputFlags();
  return 0;
}
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "isearchcontext.h"
#include "match_master.h"
#include "match_context.h"
#include "match_tools.h"
#include "match_params.h"
#include "matcher.h"
#include "sessionmanager.h"
#include <vespa/searchcore/grouping/groupingcontext.h>
#include <vespa/searchlib/engine/errorcodes.h>
#include <vespa/searchlib/engine/docsumrequest.h>
#include <vespa/searchlib/engine/searchrequest.h>
#include <vespa/searchlib/engine/searchreply.h>
#include <vespa/searchlib/features/setup.h>
#include <vespa/searchlib/fef/test/plugin/setup.h>

#include <vespa/log/log.h>
LOG_SETUP(".proton.matching.matcher");

using search::fef::Properties;
using namespace search::fef::indexproperties::matching;
using namespace search::engine;
using namespace search::grouping;
using search::DocumentMetaData;
using search::LidUsageStats;
using search::FeatureSet;
using search::attribute::IAttributeContext;
using search::fef::MatchDataLayout;
using search::fef::MatchData;
using search::fef::indexproperties::hitcollector::HeapSize;
using search::queryeval::Blueprint;
using search::queryeval::SearchIterator;
using vespalib::Doom;

namespace proton::matching {

namespace {

// used to give out empty whitelist blueprints
struct StupidMetaStore : search::IDocumentMetaStore {
    bool getGid(DocId, GlobalId &) const override { return false; }
    bool getGidEvenIfMoved(DocId, GlobalId &) const override { return false; }
    bool getLid(const GlobalId &, DocId &) const override { return false; }
    DocumentMetaData getMetaData(const GlobalId &) const override { return DocumentMetaData(); }
    void getMetaData(const BucketId &, DocumentMetaData::Vector &) const override { }
    DocId getCommittedDocIdLimit() const override { return 1; }
    DocId getNumUsedLids() const override { return 0; }
    DocId getNumActiveLids() const override { return 0; }
    uint64_t getCurrentGeneration() const override { return 0; }
    LidUsageStats getLidUsageStats() const override { return LidUsageStats(); }
    Blueprint::UP createWhiteListBlueprint() const override { return Blueprint::UP(); }
    void foreach(const search::IGidToLidMapperVisitor &) const override { }
};

FeatureSet::SP
findFeatureSet(const DocsumRequest &req, MatchToolsFactory &mtf, bool summaryFeatures)
{
    std::vector<uint32_t> docs;
    docs.reserve(req.hits.size());
    for (const auto & hit : req.hits) {
        if (hit.docid != search::endDocId) {
            docs.push_back(hit.docid);
        }
    }
    std::sort(docs.begin(), docs.end());
    return MatchMaster::getFeatureSet(mtf, docs, summaryFeatures);
}

size_t numThreads(size_t hits, size_t minHits) {
    return static_cast<size_t>(std::ceil(double(hits) / double(minHits)));
}

class LimitedThreadBundleWrapper final : public vespalib::ThreadBundle
{
public:
    LimitedThreadBundleWrapper(vespalib::ThreadBundle &threadBundle, uint32_t maxThreads) :
        _threadBundle(threadBundle),
        _maxThreads(std::min(maxThreads, static_cast<uint32_t>(threadBundle.size())))
    { }
private:
    size_t size() const override { return _maxThreads; }
    void run(const std::vector<vespalib::Runnable*> &targets) override {
        _threadBundle.run(targets);
    }
    vespalib::ThreadBundle &_threadBundle;
    const uint32_t          _maxThreads;
};

bool willNotNeedRanking(const SearchRequest & request, const GroupingContext & groupingContext) {
    return (!groupingContext.needRanking() && (request.maxhits == 0))
           || (!request.sortSpec.empty() && (request.sortSpec.find("[rank]") == vespalib::string::npos));
}

}  // namespace proton::matching::<unnamed>

FeatureSet::SP
Matcher::getFeatureSet(const DocsumRequest & req, ISearchContext & searchCtx, IAttributeContext & attrCtx,
                       SessionManager & sessionMgr, bool summaryFeatures)
{
    SessionId sessionId(&req.sessionId[0], req.sessionId.size());
    if (!sessionId.empty()) {
        const Properties &cache_props = req.propertiesMap.cacheProperties();
        bool searchSessionCached = cache_props.lookup("query").found();
        if (searchSessionCached) {
            SearchSession::SP session(sessionMgr.pickSearch(sessionId));
            if (session) {
                MatchToolsFactory &mtf = session->getMatchToolsFactory();
                FeatureSet::SP result = findFeatureSet(req, mtf, summaryFeatures);
                session->releaseEnumGuards();
                return result;
            }
        }
    }

    StupidMetaStore metaStore;
    MatchToolsFactory::UP mtf = create_match_tools_factory(req, searchCtx, attrCtx, metaStore,
                                                           req.propertiesMap.featureOverrides());
    if (!mtf->valid()) {
        LOG(warning, "getFeatureSet(%s): query execution failed (invalid query). Returning empty feature set",
                     (summaryFeatures ? "summary features" : "rank features"));
        return std::make_shared<FeatureSet>();
    }
    return findFeatureSet(req, *mtf, summaryFeatures);
}

Matcher::Matcher(const search::index::Schema &schema, const Properties &props, const vespalib::Clock &clock,
                 QueryLimiter &queryLimiter, const IConstantValueRepo &constantValueRepo, uint32_t distributionKey)
    : _indexEnv(schema, props, constantValueRepo),
      _blueprintFactory(),
      _rankSetup(),
      _viewResolver(ViewResolver::createFromSchema(schema)),
      _statsLock(),
      _stats(),
      _clock(clock),
      _queryLimiter(queryLimiter),
      _distributionKey(distributionKey)
{
    search::features::setup_search_features(_blueprintFactory);
    search::fef::test::setup_fef_test_plugin(_blueprintFactory);
    _rankSetup = std::make_shared<search::fef::RankSetup>(_blueprintFactory, _indexEnv);
    _rankSetup->configure(); // reads config values from the property map
    if (!_rankSetup->compile()) {
        throw vespalib::IllegalArgumentException("failed to compile rank setup", VESPA_STRLOC);
    }
}

MatchingStats
Matcher::getStats()
{
    std::lock_guard<std::mutex> guard(_statsLock);
    MatchingStats stats = std::move(_stats);
    _stats = std::move(MatchingStats());
    _stats.softDoomFactor(stats.softDoomFactor());
    return stats;
}

using search::fef::indexproperties::softtimeout::Enabled;
using search::fef::indexproperties::softtimeout::Factor;

std::unique_ptr<MatchToolsFactory>
Matcher::create_match_tools_factory(const search::engine::Request &request, ISearchContext &searchContext,
                                    IAttributeContext &attrContext, const search::IDocumentMetaStore &metaStore,
                                    const Properties &feature_overrides) const
{
    const Properties & rankProperties = request.propertiesMap.rankProperties();
    bool softTimeoutEnabled = Enabled::lookup(rankProperties, _rankSetup->getSoftTimeoutEnabled());
    double factor = softTimeoutEnabled
                    ? Factor::lookup(rankProperties, _stats.softDoomFactor())
                    : 0.95;
    int64_t safeLeft = request.getTimeLeft() * factor;
    fastos::TimeStamp safeDoom(fastos::ClockSystem::now() + safeLeft);
    if (softTimeoutEnabled) {
        LOG(debug, "Soft-timeout computed factor=%1.3f, used factor=%1.3f, softTimeout=%lu softDoom=%ld hardDoom=%ld",
                   _stats.softDoomFactor(), factor, safeLeft, safeDoom.ns(), request.getTimeOfDoom().ns());
    }
    return std::make_unique<MatchToolsFactory>(_queryLimiter, vespalib::Doom(_clock, safeDoom),
                                               vespalib::Doom(_clock, request.getTimeOfDoom()), searchContext,
                                               attrContext, request.getStackRef(), request.location, _viewResolver,
                                               metaStore, _indexEnv, *_rankSetup, rankProperties, feature_overrides);
}

SearchReply::UP
Matcher::handleGroupingSession(SessionManager &sessionMgr, GroupingContext & groupingContext,
                               GroupingSession::UP groupingSession)
{
    SearchReply::UP reply = std::make_unique<SearchReply>();
    groupingSession->continueExecution(groupingContext);
    groupingContext.getResult().swap(reply->groupResult);
    if (!groupingSession->finished()) {
        sessionMgr.insert(std::move(groupingSession));
    }
    return reply;
}

size_t
Matcher::computeNumThreadsPerSearch(Blueprint::HitEstimate hits, const Properties & rankProperties) const {
    size_t threads = NumThreadsPerSearch::lookup(rankProperties, _rankSetup->getNumThreadsPerSearch());
    uint32_t minHitsPerThread = MinHitsPerThread::lookup(rankProperties, _rankSetup->getMinHitsPerThread());
    if ((threads > 1) && (minHitsPerThread > 0)) {
        threads = (hits.empty) ? 1 : std::min(threads, numThreads(hits.estHits, minHitsPerThread));
    }
    return threads;
}

SearchReply::UP
Matcher::match(const SearchRequest &request, vespalib::ThreadBundle &threadBundle,
               ISearchContext &searchContext, IAttributeContext &attrContext, SessionManager &sessionMgr,
               const search::IDocumentMetaStore &metaStore, SearchSession::OwnershipBundle &&owned_objects)
{
    fastos::StopWatch total_matching_time;
    total_matching_time.start();
    MatchingStats my_stats;
    SearchReply::UP reply = std::make_unique<SearchReply>();
    { // we want to measure full set-up and tear-down time as part of
      // collateral time
        GroupingContext groupingContext(_clock, request.getTimeOfDoom(),
                                        &request.groupSpec[0], request.groupSpec.size());
        SessionId sessionId(&request.sessionId[0], request.sessionId.size());
        bool shouldCacheSearchSession = false;
        bool shouldCacheGroupingSession = false;
        if (!sessionId.empty()) {
            const Properties &cache_props = request.propertiesMap.cacheProperties();
            shouldCacheGroupingSession = cache_props.lookup("grouping").found();
            shouldCacheSearchSession = cache_props.lookup("query").found();
            if (shouldCacheGroupingSession) {
                GroupingSession::UP session(sessionMgr.pickGrouping(sessionId));
                if (session) {
                    return handleGroupingSession(sessionMgr, groupingContext, std::move(session));
                }
            }
        }
        const Properties *feature_overrides = &request.propertiesMap.featureOverrides();
        if (shouldCacheSearchSession) {
            owned_objects.feature_overrides = std::make_unique<Properties>(*feature_overrides);
            feature_overrides = owned_objects.feature_overrides.get();
        }
        MatchToolsFactory::UP mtf = create_match_tools_factory(request, searchContext, attrContext,
                                                               metaStore, *feature_overrides);
        if (!mtf->valid()) {
            reply->errorCode = ECODE_QUERY_PARSE_ERROR;
            reply->errorMessage = "query execution failed (invalid query)";
            return reply;
        }

        const Properties & rankProperties = request.propertiesMap.rankProperties();
        uint32_t heapSize = HeapSize::lookup(rankProperties, _rankSetup->getHeapSize());

        MatchParams params(searchContext.getDocIdLimit(), heapSize, _rankSetup->getArraySize(),
                           _rankSetup->getRankScoreDropLimit(), request.offset, request.maxhits,
                           !_rankSetup->getSecondPhaseRank().empty(), !willNotNeedRanking(request, groupingContext));

        ResultProcessor rp(attrContext, metaStore, sessionMgr, groupingContext, sessionId,
                           request.sortSpec, params.offset, params.hits, request.should_drop_sort_data());

        size_t numThreadsPerSearch = computeNumThreadsPerSearch(mtf->estimate(), rankProperties);
        LimitedThreadBundleWrapper limitedThreadBundle(threadBundle, numThreadsPerSearch);
        MatchMaster master;
        uint32_t numSearchPartitions = NumSearchPartitions::lookup(rankProperties,
                                                                   _rankSetup->getNumSearchPartitions());
        ResultProcessor::Result::UP result = master.match(params, limitedThreadBundle, *mtf, rp,
                                                          _distributionKey, numSearchPartitions);
        my_stats = MatchMaster::getStats(std::move(master));

        bool wasLimited = mtf->match_limiter().was_limited();
        size_t spaceEstimate = (my_stats.softDoomed())
                               ? my_stats.docidSpaceCovered()
                               : mtf->match_limiter().getDocIdSpaceEstimate();
        uint32_t estHits = mtf->estimate().estHits;
        if (shouldCacheSearchSession && ((result->_numFs4Hits != 0) || shouldCacheGroupingSession)) {
            SearchSession::SP session = std::make_shared<SearchSession>(sessionId, request.getTimeOfDoom(),
                                                                        std::move(mtf), std::move(owned_objects));
            session->releaseEnumGuards();
            sessionMgr.insert(std::move(session));
        }
        reply = std::move(result->_reply);

        uint32_t numActiveLids = metaStore.getNumActiveLids();
        // note: this is actually totalSpace+1, since 0 is reserved
        uint32_t totalSpace = metaStore.getCommittedDocIdLimit();
        LOG(debug, "docid limit = %d", totalSpace);
        LOG(debug, "num active lids = %d", numActiveLids);
        LOG(debug, "space Estimate = %zd", spaceEstimate);
        if (spaceEstimate >= totalSpace) {
            // estimate is too high, clamp it
            spaceEstimate = totalSpace;
        } else {
            // account for docid 0 reserved
            spaceEstimate += 1;
        }
        size_t covered = (spaceEstimate *  numActiveLids) / totalSpace;
        LOG(debug, "covered = %zd", covered);

        SearchReply::Coverage & coverage = reply->coverage;
        coverage.setActive(numActiveLids);
        //TODO this should be calculated with ClusterState calculator.
        coverage.setSoonActive(numActiveLids);
        coverage.setCovered(covered);
        if (wasLimited) {
            coverage.degradeMatchPhase();
            LOG(debug, "was limited, degraded from match phase");
        }
        if (my_stats.softDoomed()) {
            coverage.degradeTimeout();
            LOG(debug, "soft doomed, degraded from timeout covered = %lu", coverage.getCovered());
        }
        LOG(debug, "numThreadsPerSearch = %zu. Configured = %d, estimated hits=%d, totalHits=%ld , rankprofile=%s",
            numThreadsPerSearch, _rankSetup->getNumThreadsPerSearch(), estHits, reply->totalHitCount,
            request.ranking.c_str());
    }
    total_matching_time.stop();
    my_stats.queryCollateralTime(total_matching_time.elapsed().sec() - my_stats.queryLatencyAvg());
    {
        fastos::TimeStamp duration = request.getTimeUsed();
        std::lock_guard<std::mutex> guard(_statsLock);
        _stats.add(my_stats);
        if (my_stats.softDoomed()) {
            double old = _stats.softDoomFactor();
            fastos::TimeStamp softLimit = uint64_t((1.0 - _rankSetup->getSoftTimeoutTailCost()) * request.getTimeout());
            _stats.updatesoftDoomFactor(request.getTimeout(), softLimit, duration - my_stats.doomOvertime());
            LOG(info, "Triggered softtimeout factor adjustment. request=%1.3f, doomOvertime=%1.3f, limit=%1.3f and duration=%1.3f, rankprofile=%s"
                      ", factor adjusted from %1.3f to %1.3f",
                request.getTimeout().sec(), my_stats.doomOvertime().sec(), softLimit.sec(), duration.sec(),
                request.ranking.c_str(), old, _stats.softDoomFactor());
        }
    }
    return reply;
}

FeatureSet::SP
Matcher::getSummaryFeatures(const DocsumRequest & req, ISearchContext & searchCtx,
                            IAttributeContext & attrCtx, SessionManager &sessionMgr)
{
    return getFeatureSet(req, searchCtx, attrCtx, sessionMgr, true);
}

FeatureSet::SP
Matcher::getRankFeatures(const DocsumRequest & req, ISearchContext & searchCtx,
                         IAttributeContext & attrCtx, SessionManager &sessionMgr)
{
    return getFeatureSet(req, searchCtx, attrCtx, sessionMgr, false);
}

}
<commit_msg>Avoid underflow<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "isearchcontext.h"
#include "match_master.h"
#include "match_context.h"
#include "match_tools.h"
#include "match_params.h"
#include "matcher.h"
#include "sessionmanager.h"
#include <vespa/searchcore/grouping/groupingcontext.h>
#include <vespa/searchlib/engine/errorcodes.h>
#include <vespa/searchlib/engine/docsumrequest.h>
#include <vespa/searchlib/engine/searchrequest.h>
#include <vespa/searchlib/engine/searchreply.h>
#include <vespa/searchlib/features/setup.h>
#include <vespa/searchlib/fef/test/plugin/setup.h>

#include <vespa/log/log.h>
LOG_SETUP(".proton.matching.matcher");

using search::fef::Properties;
using namespace search::fef::indexproperties::matching;
using namespace search::engine;
using namespace search::grouping;
using search::DocumentMetaData;
using search::LidUsageStats;
using search::FeatureSet;
using search::attribute::IAttributeContext;
using search::fef::MatchDataLayout;
using search::fef::MatchData;
using search::fef::indexproperties::hitcollector::HeapSize;
using search::queryeval::Blueprint;
using search::queryeval::SearchIterator;
using vespalib::Doom;

namespace proton::matching {

namespace {

// used to give out empty whitelist blueprints
struct StupidMetaStore : search::IDocumentMetaStore {
    bool getGid(DocId, GlobalId &) const override { return false; }
    bool getGidEvenIfMoved(DocId, GlobalId &) const override { return false; }
    bool getLid(const GlobalId &, DocId &) const override { return false; }
    DocumentMetaData getMetaData(const GlobalId &) const override { return DocumentMetaData(); }
    void getMetaData(const BucketId &, DocumentMetaData::Vector &) const override { }
    DocId getCommittedDocIdLimit() const override { return 1; }
    DocId getNumUsedLids() const override { return 0; }
    DocId getNumActiveLids() const override { return 0; }
    uint64_t getCurrentGeneration() const override { return 0; }
    LidUsageStats getLidUsageStats() const override { return LidUsageStats(); }
    Blueprint::UP createWhiteListBlueprint() const override { return Blueprint::UP(); }
    void foreach(const search::IGidToLidMapperVisitor &) const override { }
};

FeatureSet::SP
findFeatureSet(const DocsumRequest &req, MatchToolsFactory &mtf, bool summaryFeatures)
{
    std::vector<uint32_t> docs;
    docs.reserve(req.hits.size());
    for (const auto & hit : req.hits) {
        if (hit.docid != search::endDocId) {
            docs.push_back(hit.docid);
        }
    }
    std::sort(docs.begin(), docs.end());
    return MatchMaster::getFeatureSet(mtf, docs, summaryFeatures);
}

size_t numThreads(size_t hits, size_t minHits) {
    return static_cast<size_t>(std::ceil(double(hits) / double(minHits)));
}

class LimitedThreadBundleWrapper final : public vespalib::ThreadBundle
{
public:
    LimitedThreadBundleWrapper(vespalib::ThreadBundle &threadBundle, uint32_t maxThreads) :
        _threadBundle(threadBundle),
        _maxThreads(std::min(maxThreads, static_cast<uint32_t>(threadBundle.size())))
    { }
private:
    size_t size() const override { return _maxThreads; }
    void run(const std::vector<vespalib::Runnable*> &targets) override {
        _threadBundle.run(targets);
    }
    vespalib::ThreadBundle &_threadBundle;
    const uint32_t          _maxThreads;
};

bool willNotNeedRanking(const SearchRequest & request, const GroupingContext & groupingContext) {
    return (!groupingContext.needRanking() && (request.maxhits == 0))
           || (!request.sortSpec.empty() && (request.sortSpec.find("[rank]") == vespalib::string::npos));
}

}  // namespace proton::matching::<unnamed>

FeatureSet::SP
Matcher::getFeatureSet(const DocsumRequest & req, ISearchContext & searchCtx, IAttributeContext & attrCtx,
                       SessionManager & sessionMgr, bool summaryFeatures)
{
    SessionId sessionId(&req.sessionId[0], req.sessionId.size());
    if (!sessionId.empty()) {
        const Properties &cache_props = req.propertiesMap.cacheProperties();
        bool searchSessionCached = cache_props.lookup("query").found();
        if (searchSessionCached) {
            SearchSession::SP session(sessionMgr.pickSearch(sessionId));
            if (session) {
                MatchToolsFactory &mtf = session->getMatchToolsFactory();
                FeatureSet::SP result = findFeatureSet(req, mtf, summaryFeatures);
                session->releaseEnumGuards();
                return result;
            }
        }
    }

    StupidMetaStore metaStore;
    MatchToolsFactory::UP mtf = create_match_tools_factory(req, searchCtx, attrCtx, metaStore,
                                                           req.propertiesMap.featureOverrides());
    if (!mtf->valid()) {
        LOG(warning, "getFeatureSet(%s): query execution failed (invalid query). Returning empty feature set",
                     (summaryFeatures ? "summary features" : "rank features"));
        return std::make_shared<FeatureSet>();
    }
    return findFeatureSet(req, *mtf, summaryFeatures);
}

Matcher::Matcher(const search::index::Schema &schema, const Properties &props, const vespalib::Clock &clock,
                 QueryLimiter &queryLimiter, const IConstantValueRepo &constantValueRepo, uint32_t distributionKey)
    : _indexEnv(schema, props, constantValueRepo),
      _blueprintFactory(),
      _rankSetup(),
      _viewResolver(ViewResolver::createFromSchema(schema)),
      _statsLock(),
      _stats(),
      _clock(clock),
      _queryLimiter(queryLimiter),
      _distributionKey(distributionKey)
{
    search::features::setup_search_features(_blueprintFactory);
    search::fef::test::setup_fef_test_plugin(_blueprintFactory);
    _rankSetup = std::make_shared<search::fef::RankSetup>(_blueprintFactory, _indexEnv);
    _rankSetup->configure(); // reads config values from the property map
    if (!_rankSetup->compile()) {
        throw vespalib::IllegalArgumentException("failed to compile rank setup", VESPA_STRLOC);
    }
}

MatchingStats
Matcher::getStats()
{
    std::lock_guard<std::mutex> guard(_statsLock);
    MatchingStats stats = std::move(_stats);
    _stats = std::move(MatchingStats());
    _stats.softDoomFactor(stats.softDoomFactor());
    return stats;
}

using search::fef::indexproperties::softtimeout::Enabled;
using search::fef::indexproperties::softtimeout::Factor;

std::unique_ptr<MatchToolsFactory>
Matcher::create_match_tools_factory(const search::engine::Request &request, ISearchContext &searchContext,
                                    IAttributeContext &attrContext, const search::IDocumentMetaStore &metaStore,
                                    const Properties &feature_overrides) const
{
    const Properties & rankProperties = request.propertiesMap.rankProperties();
    bool softTimeoutEnabled = Enabled::lookup(rankProperties, _rankSetup->getSoftTimeoutEnabled());
    double factor = softTimeoutEnabled
                    ? Factor::lookup(rankProperties, _stats.softDoomFactor())
                    : 0.95;
    int64_t safeLeft = request.getTimeLeft() * factor;
    fastos::TimeStamp safeDoom(fastos::ClockSystem::now() + safeLeft);
    if (softTimeoutEnabled) {
        LOG(debug, "Soft-timeout computed factor=%1.3f, used factor=%1.3f, softTimeout=%lu softDoom=%ld hardDoom=%ld",
                   _stats.softDoomFactor(), factor, safeLeft, safeDoom.ns(), request.getTimeOfDoom().ns());
    }
    return std::make_unique<MatchToolsFactory>(_queryLimiter, vespalib::Doom(_clock, safeDoom),
                                               vespalib::Doom(_clock, request.getTimeOfDoom()), searchContext,
                                               attrContext, request.getStackRef(), request.location, _viewResolver,
                                               metaStore, _indexEnv, *_rankSetup, rankProperties, feature_overrides);
}

SearchReply::UP
Matcher::handleGroupingSession(SessionManager &sessionMgr, GroupingContext & groupingContext,
                               GroupingSession::UP groupingSession)
{
    SearchReply::UP reply = std::make_unique<SearchReply>();
    groupingSession->continueExecution(groupingContext);
    groupingContext.getResult().swap(reply->groupResult);
    if (!groupingSession->finished()) {
        sessionMgr.insert(std::move(groupingSession));
    }
    return reply;
}

size_t
Matcher::computeNumThreadsPerSearch(Blueprint::HitEstimate hits, const Properties & rankProperties) const {
    size_t threads = NumThreadsPerSearch::lookup(rankProperties, _rankSetup->getNumThreadsPerSearch());
    uint32_t minHitsPerThread = MinHitsPerThread::lookup(rankProperties, _rankSetup->getMinHitsPerThread());
    if ((threads > 1) && (minHitsPerThread > 0)) {
        threads = (hits.empty) ? 1 : std::min(threads, numThreads(hits.estHits, minHitsPerThread));
    }
    return threads;
}

SearchReply::UP
Matcher::match(const SearchRequest &request, vespalib::ThreadBundle &threadBundle,
               ISearchContext &searchContext, IAttributeContext &attrContext, SessionManager &sessionMgr,
               const search::IDocumentMetaStore &metaStore, SearchSession::OwnershipBundle &&owned_objects)
{
    fastos::StopWatch total_matching_time;
    total_matching_time.start();
    MatchingStats my_stats;
    SearchReply::UP reply = std::make_unique<SearchReply>();
    { // we want to measure full set-up and tear-down time as part of
      // collateral time
        GroupingContext groupingContext(_clock, request.getTimeOfDoom(),
                                        &request.groupSpec[0], request.groupSpec.size());
        SessionId sessionId(&request.sessionId[0], request.sessionId.size());
        bool shouldCacheSearchSession = false;
        bool shouldCacheGroupingSession = false;
        if (!sessionId.empty()) {
            const Properties &cache_props = request.propertiesMap.cacheProperties();
            shouldCacheGroupingSession = cache_props.lookup("grouping").found();
            shouldCacheSearchSession = cache_props.lookup("query").found();
            if (shouldCacheGroupingSession) {
                GroupingSession::UP session(sessionMgr.pickGrouping(sessionId));
                if (session) {
                    return handleGroupingSession(sessionMgr, groupingContext, std::move(session));
                }
            }
        }
        const Properties *feature_overrides = &request.propertiesMap.featureOverrides();
        if (shouldCacheSearchSession) {
            owned_objects.feature_overrides = std::make_unique<Properties>(*feature_overrides);
            feature_overrides = owned_objects.feature_overrides.get();
        }
        MatchToolsFactory::UP mtf = create_match_tools_factory(request, searchContext, attrContext,
                                                               metaStore, *feature_overrides);
        if (!mtf->valid()) {
            reply->errorCode = ECODE_QUERY_PARSE_ERROR;
            reply->errorMessage = "query execution failed (invalid query)";
            return reply;
        }

        const Properties & rankProperties = request.propertiesMap.rankProperties();
        uint32_t heapSize = HeapSize::lookup(rankProperties, _rankSetup->getHeapSize());

        MatchParams params(searchContext.getDocIdLimit(), heapSize, _rankSetup->getArraySize(),
                           _rankSetup->getRankScoreDropLimit(), request.offset, request.maxhits,
                           !_rankSetup->getSecondPhaseRank().empty(), !willNotNeedRanking(request, groupingContext));

        ResultProcessor rp(attrContext, metaStore, sessionMgr, groupingContext, sessionId,
                           request.sortSpec, params.offset, params.hits, request.should_drop_sort_data());

        size_t numThreadsPerSearch = computeNumThreadsPerSearch(mtf->estimate(), rankProperties);
        LimitedThreadBundleWrapper limitedThreadBundle(threadBundle, numThreadsPerSearch);
        MatchMaster master;
        uint32_t numSearchPartitions = NumSearchPartitions::lookup(rankProperties,
                                                                   _rankSetup->getNumSearchPartitions());
        ResultProcessor::Result::UP result = master.match(params, limitedThreadBundle, *mtf, rp,
                                                          _distributionKey, numSearchPartitions);
        my_stats = MatchMaster::getStats(std::move(master));

        bool wasLimited = mtf->match_limiter().was_limited();
        size_t spaceEstimate = (my_stats.softDoomed())
                               ? my_stats.docidSpaceCovered()
                               : mtf->match_limiter().getDocIdSpaceEstimate();
        uint32_t estHits = mtf->estimate().estHits;
        if (shouldCacheSearchSession && ((result->_numFs4Hits != 0) || shouldCacheGroupingSession)) {
            SearchSession::SP session = std::make_shared<SearchSession>(sessionId, request.getTimeOfDoom(),
                                                                        std::move(mtf), std::move(owned_objects));
            session->releaseEnumGuards();
            sessionMgr.insert(std::move(session));
        }
        reply = std::move(result->_reply);

        uint32_t numActiveLids = metaStore.getNumActiveLids();
        // note: this is actually totalSpace+1, since 0 is reserved
        uint32_t totalSpace = metaStore.getCommittedDocIdLimit();
        LOG(debug, "docid limit = %d", totalSpace);
        LOG(debug, "num active lids = %d", numActiveLids);
        LOG(debug, "space Estimate = %zd", spaceEstimate);
        if (spaceEstimate >= totalSpace) {
            // estimate is too high, clamp it
            spaceEstimate = totalSpace;
        } else {
            // account for docid 0 reserved
            spaceEstimate += 1;
        }
        size_t covered = (spaceEstimate *  numActiveLids) / totalSpace;
        LOG(debug, "covered = %zd", covered);

        SearchReply::Coverage & coverage = reply->coverage;
        coverage.setActive(numActiveLids);
        //TODO this should be calculated with ClusterState calculator.
        coverage.setSoonActive(numActiveLids);
        coverage.setCovered(covered);
        if (wasLimited) {
            coverage.degradeMatchPhase();
            LOG(debug, "was limited, degraded from match phase");
        }
        if (my_stats.softDoomed()) {
            coverage.degradeTimeout();
            LOG(debug, "soft doomed, degraded from timeout covered = %lu", coverage.getCovered());
        }
        LOG(debug, "numThreadsPerSearch = %zu. Configured = %d, estimated hits=%d, totalHits=%ld , rankprofile=%s",
            numThreadsPerSearch, _rankSetup->getNumThreadsPerSearch(), estHits, reply->totalHitCount,
            request.ranking.c_str());
    }
    total_matching_time.stop();
    my_stats.queryCollateralTime(total_matching_time.elapsed().sec() - my_stats.queryLatencyAvg());
    {
        fastos::TimeStamp duration = request.getTimeUsed();
        std::lock_guard<std::mutex> guard(_statsLock);
        _stats.add(my_stats);
        if (my_stats.softDoomed()) {
            double old = _stats.softDoomFactor();
            fastos::TimeStamp softLimit = uint64_t((1.0 - _rankSetup->getSoftTimeoutTailCost()) * request.getTimeout());
            fastos::TimeStamp adjustedDuration = duration - my_stats.doomOvertime();
            if (adjustedDuration < 0) {
                adjustedDuration = 0;
            }
            _stats.updatesoftDoomFactor(request.getTimeout(), softLimit, adjustedDuration);
            LOG(info, "Triggered softtimeout factor adjustment. request=%1.3f, doomOvertime=%1.3f, limit=%1.3f and duration=%1.3f, rankprofile=%s"
                      ", factor adjusted from %1.3f to %1.3f",
                request.getTimeout().sec(), my_stats.doomOvertime().sec(), softLimit.sec(), duration.sec(),
                request.ranking.c_str(), old, _stats.softDoomFactor());
        }
    }
    return reply;
}

FeatureSet::SP
Matcher::getSummaryFeatures(const DocsumRequest & req, ISearchContext & searchCtx,
                            IAttributeContext & attrCtx, SessionManager &sessionMgr)
{
    return getFeatureSet(req, searchCtx, attrCtx, sessionMgr, true);
}

FeatureSet::SP
Matcher::getRankFeatures(const DocsumRequest & req, ISearchContext & searchCtx,
                         IAttributeContext & attrCtx, SessionManager &sessionMgr)
{
    return getFeatureSet(req, searchCtx, attrCtx, sessionMgr, false);
}

}
<|endoftext|>


<commit_before>#include "FAST/Tests/catch.hpp"
#include "FAST/DeviceManager.hpp"
#include "NonLocalMeans.hpp"

namespace fast{

    TEST_CASE("No input given to NonLocalMeans throws exception", "[fast][NonLocalMeans]") {
        NonLocalMeans::pointer filter = NonLocalMeans::New();
        CHECK_THROWS(filter->update());
    }

    TEST_CASE("Negative or zero sigma input throws exception in NonLocalMeans", "[fast][NonLocalMeans]") {
        NonLocalMeans::pointer filter = NonLocalMeans::New();

        CHECK_THROWS(filter->setWindowSize(-4));
        CHECK_THROWS(filter->setWindowSize(0));
        CHECK_THROWS(filter->setGroupSize(-4));
        CHECK_THROWS(filter->setGroupSize(0));
        CHECK_THROWS(filter->setK(-4));
        CHECK_THROWS(filter->setK(0));
        CHECK_THROWS(filter->setEuclid(-4));
        CHECK_THROWS(filter->setEuclid(0));
        CHECK_THROWS(filter->setSigma(-4));
        CHECK_THROWS(filter->setSigma(0));
        CHECK_THROWS(filter->setDenoiseStrength(-4));
        CHECK_THROWS(filter->setDenoiseStrength(0));
    }

    TEST_CASE("Even input as window size or group size throws exception in NonLocalMeans", "[fast][NonLocalMeans]") {
       NonLocalMeans::pointer filter = NonLocalMeans::New();

        CHECK_THROWS(filter->setWindowSize(2));
        CHECK_THROWS(filter->setGroupSize(2));
    }
}<commit_msg>fixed a failing NLM test<commit_after>#include "FAST/Tests/catch.hpp"
#include "FAST/DeviceManager.hpp"
#include "NonLocalMeans.hpp"

namespace fast{

    TEST_CASE("No input given to NonLocalMeans throws exception", "[fast][NonLocalMeans]") {
        NonLocalMeans::pointer filter = NonLocalMeans::New();
        CHECK_THROWS(filter->update());
    }

    TEST_CASE("Negative or zero sigma input throws exception in NonLocalMeans", "[fast][NonLocalMeans]") {
        NonLocalMeans::pointer filter = NonLocalMeans::New();

        CHECK_THROWS(filter->setWindowSize(-4));
        CHECK_THROWS(filter->setWindowSize(0));
        CHECK_THROWS(filter->setGroupSize(-4));
        CHECK_THROWS(filter->setGroupSize(0));
        CHECK_THROWS(filter->setK(-4));
        CHECK_THROWS(filter->setEuclid(-4));
        CHECK_THROWS(filter->setSigma(-4));
        CHECK_THROWS(filter->setSigma(0));
        CHECK_THROWS(filter->setDenoiseStrength(-4));
        CHECK_THROWS(filter->setDenoiseStrength(0));
    }

    TEST_CASE("Even input as window size or group size throws exception in NonLocalMeans", "[fast][NonLocalMeans]") {
       NonLocalMeans::pointer filter = NonLocalMeans::New();

        CHECK_THROWS(filter->setWindowSize(2));
        CHECK_THROWS(filter->setGroupSize(2));
    }
}
<|endoftext|>


<commit_before>/*
 * StackAcquisition.cpp
 *
 *  Created on: May 10, 2010
 *      Author: Nathan Clack <clackn@janelia.hhmi.org>
 */
/*
 * Copyright 2010 Howard Hughes Medical Institute.
 * All rights reserved.
 * Use is subject to Janelia Farm Research Campus Software Copyright 1.1
 * license terms (http://license.janelia.org/license/jfrc_copyright_1_1.html).
 */

#include "common.h"
#include "StackAcquisition.h"
#include "Video.h"
#include "frame.h"
#include "devices\digitizer.h"
#include "devices\Microscope.h"

#if 0
#define DBG(...) debug(__VA_ARGS__);
#else
#define DBG(...)
#endif

#define DIGWRN( expr )  (niscope_chk( vi, expr, #expr, __FILE__, __LINE__, warning ))
#define DIGERR( expr )  (niscope_chk( vi, expr, #expr, __FILE__, __LINE__, error   ))
#define DIGJMP( expr )  goto_if_fail(VI_SUCCESS == niscope_chk( vi, expr, #expr, __FILE__, __LINE__, warning ), Error)
#define DAQWRN( expr )  (Guarded_DAQmx( (expr), #expr, __FILE__, __LINE__, warning))
#define DAQERR( expr )  (Guarded_DAQmx( (expr), #expr, __FILE__, __LINE__, error  ))
#define DAQJMP( expr )  goto_if_fail( 0==DAQWRN(expr), Error)

#define CHKERR( expr )  if(expr) {error("%s(%d)"ENDL"\tExpression indicated failure:"ENDL"\t%s"ENDL,__FILE__,__LINE__,#expr);} //( (expr), #expr, error  ))
#define CHKJMP( expr )  goto_if((expr),Error)

#if 0
#define SCANNER_DEBUG_FAIL_WHEN_FULL
#else
#define SCANNER_DEBUG_WAIT_WHEN_FULL
#endif

#ifdef SCANNER_DEBUG_FAIL_WHEN_FULL
#define SCANNER_PUSH(...) Chan_Next_Try(__VA_ARGS__)
#elif defined(SCANNER_DEBUG_WAIT_WHEN_FULL)
#define SCANNER_PUSH(...) Chan_Next(__VA_ARGS__)
#else
#error("An overflow behavior for the scanner should be specified");
#endif

namespace fetch
{

  namespace task
  {

    //
    // StackAcquisition -  microscope task
    //

    namespace microscope {

      //Upcasting
      unsigned int StackAcquisition::config(IDevice *d) {return config(dynamic_cast<device::Microscope*>(d));}
      unsigned int StackAcquisition::run   (IDevice *d) {return run   (dynamic_cast<device::Microscope*>(d));}

      unsigned int StackAcquisition::config(device::Microscope *d)
      {
        static task::scanner::ScanStack<i16> grabstack;
        std::string filename;

        Guarded_Assert(d);

        //Assemble pipeline here
        IDevice *cur;
        cur = d->configPipeline();

        CHKJMP( !d->file_series.ensurePathExists() );

        d->file_series.inc();
        filename = d->stack_filename();
        IDevice::connect(&d->disk,0,cur,0);
        Guarded_Assert( d->disk.close()==0 );
        //Guarded_Assert( d->disk.open(filename,"w")==0);

        d->__scan_agent.arm(&grabstack,&d->scanner);                      // why was this arm_nowait?

        return 1; //success
Error:
        return 0; //failure
      }

      static int _handle_wait_for_result(DWORD result, const char *msg)
      {
          return_val_if( result == WAIT_OBJECT_0  , 0 );
          return_val_if( result == WAIT_OBJECT_0+1, 1 );
          Guarded_Assert_WinErr( result != WAIT_FAILED );
          if(result == WAIT_ABANDONED_0)
              warning("StackAcquisition: Wait 0 abandoned"ENDL"\t%s"ENDL, msg);
          if(result == WAIT_ABANDONED_0+1)
              warning("StackAcquisition: Wait 1 abandoned"ENDL"\t%s"ENDL, msg);

          if(result == WAIT_TIMEOUT)
              warning("StackAcquisition: Wait timeout"ENDL"\t%s"ENDL, msg);

          Guarded_Assert_WinErr( result != WAIT_FAILED );

          return -1;
      }

      unsigned int StackAcquisition::run(device::Microscope *dc)
      {
        std::string filename;
        unsigned int eflag = 0; // success

        Guarded_Assert(dc->__scan_agent.is_runnable());
        //Guarded_Assert(dc->__io_agent.is_running());

        filename = dc->stack_filename();

        dc->file_series.ensurePathExists();
        eflag |= dc->disk.open(filename,"w");
        if(eflag)
          return eflag;

        eflag |= dc->runPipeline();
        eflag |= dc->__scan_agent.run() != 1;

        //Chan_Wait_For_Writer_Count(dc->__scan_agent._owner->_out->contents[0],1);

        { HANDLE hs[] = {dc->__scan_agent._thread,
                         dc->__self_agent._notify_stop};
          DWORD res;
          int   t;

          // wait for scan to complete (or cancel)
          res = WaitForMultipleObjects(2,hs,FALSE,INFINITE);
          t = _handle_wait_for_result(res,"StackAcquisition::run - Wait for scanner to finish.");
          switch(t)
          { case 0:       // in this case, the scanner thread stopped.  Nothing left to do.
              eflag |= 0; // success
              //break;
            case 1:       // in this case, the stop event triggered and must be propagated.
              eflag |= dc->__scan_agent.stop(SCANNER2D_DEFAULT_TIMEOUT) != 1;
              break;
            default:      // in this case, there was a timeout or abandoned wait
              eflag |= 1; //failure
          }

          // Output metadata and Increment file
          eflag |= dc->disk.close();
          dc->write_stack_metadata();
          dc->file_series.inc();

          //dc->connect(&dc->disk,0,dc->pipelineEnd(),0);

        }
        eflag |= dc->stopPipeline(); // wait till the  pipeline stops
        return eflag;
      }

    }  // namespace microscope

    //
    // ScanStack - scanner task
    //

    namespace scanner
    {

      template class ScanStack<i8 >;
      template class ScanStack<i16>;

      // upcasts
      template<class TPixel> unsigned int ScanStack<TPixel>::config (IDevice *d) {return config(dynamic_cast<device::Scanner3D*>(d));}
      template<class TPixel> unsigned int ScanStack<TPixel>::update (IDevice *d) {return update(dynamic_cast<device::Scanner3D*>(d));}

      template<class TPixel> unsigned int ScanStack<TPixel>::run    (IDevice *d)
      {
        device::Scanner3D *s = dynamic_cast<device::Scanner3D*>(d);
        device::Digitizer::Config digcfg = s->_scanner2d._digitizer.get_config();
        switch(digcfg.kind())
        {
        case cfg::device::Digitizer_DigitizerType_NIScope:
          return run_niscope(s);
          break;
        case cfg::device::Digitizer_DigitizerType_Alazar:
          return run_alazar(s);
          break;
        case cfg::device::Digitizer_DigitizerType_Simulated:
          return run_simulated(s);
          break;
        default:
          warning("ScanStack<>::run() - Got invalid kind() for Digitizer.get_config"ENDL);
        }
        return 0; //failure
      }

      template<class TPixel>
        unsigned int
        ScanStack<TPixel>::
        config(device::Scanner3D *d)
        {
          d->onConfigTask();
          debug("Scanner3D configured for StackAcquisition<%s>"ENDL, TypeStr<TPixel> ());
          return 1; //success
        }

      template<class TPixel>
        unsigned int
        ScanStack<TPixel>::
        update(device::Scanner3D *scanner)
        {
          scanner->generateAO();
          return 1;
        }

      template<class TPixel>
        unsigned int
        ScanStack<TPixel>::run_niscope(device::Scanner3D *d)
        {
          Chan *qdata = Chan_Open(d->_out->contents[0],CHAN_WRITE),
               *qwfm  = Chan_Open(d->_out->contents[1],CHAN_WRITE);
          Frame *frm = NULL;
          Frame_With_Interleaved_Lines ref;
          struct niScope_wfmInfo *wfm = NULL;
          ViInt32 nwfm;
          ViInt32 width;
          int i = 0, status = 1; // status == 0 implies success, error otherwise
          size_t nbytes, nbytes_info;
          f64 z_um,ummax,ummin,umstep;

          TicTocTimer outer_clock = tic(), inner_clock = tic();
          double dt_in = 0.0, dt_out = 0.0;

          device::NIScopeDigitizer *dig = d->_scanner2d._digitizer._niscope;
          device::NIScopeDigitizer::Config digcfg = dig->get_config();

          ViSession vi = dig->_vi;
          ViChar *chan = const_cast<ViChar*>(digcfg.chan_names().c_str());

          ref = _describe_actual_frame_niscope<TPixel>(
            dig,                                 // NISCope Digitizer
            d->_scanner2d.get_config().nscans(), // number of scans
            &width,                              // width in pixels (queried from board)
            &nwfm);                              // this should be the number of scans (queried from board)
          nbytes = ref.size_bytes();
          nbytes_info = nwfm * sizeof(struct niScope_wfmInfo);
          //
          Chan_Resize(qdata, nbytes);
          Chan_Resize(qwfm, nbytes_info);
          frm = (Frame*) Chan_Token_Buffer_Alloc(qdata);
          wfm = (struct niScope_wfmInfo*) Chan_Token_Buffer_Alloc(qwfm);
          nbytes = Chan_Buffer_Size_Bytes(qdata);
          nbytes_info = Chan_Buffer_Size_Bytes(qwfm);
          //
          ref.format(frm);

          d->_zpiezo.getScanRange(&ummin,&ummax,&umstep);
          d->_zpiezo.moveTo(ummin); // reset to starting position

          d->generateAORampZ((float)ummin);
          d->writeAO();
          d->_scanner2d._shutter.Open();
          CHKJMP(d->_scanner2d._daq.startAO());
          for(z_um=ummin+umstep;z_um<=ummax && !d->_agent->is_stopping();z_um+=umstep)
          {
            CHKJMP(d->_scanner2d._daq.startCLK());
            DIGJMP(niScope_InitiateAcquisition(vi));

            dt_out = toc(&outer_clock);
            toc(&inner_clock);
#if 1
            DIGJMP(Fetch<TPixel> (vi, chan, SCANNER_STACKACQ_TASK_FETCH_TIMEOUT,//10.0, //(-1=infinite) (0.0=immediate) // seconds
                                  width,
                                  (TPixel*) frm->data,
                                  wfm));
#endif

            // Push the acquired data down the output pipes
            DBG("Task: StackAcquisition<%s>: pushing wfm"ENDL, TypeStr<TPixel> ());
            Chan_Next_Try(qwfm,(void**)&wfm,nbytes_info);
            DBG("Task: StackAcquisition<%s>: pushing frame"ENDL, TypeStr<TPixel> ());
            if(CHAN_FAILURE( SCANNER_PUSH(qdata,(void**)&frm,nbytes) ))
            { warning("(%s:%d) Scanner output frame queue overflowed."ENDL"\tAborting stack acquisition task."ENDL,__FILE__,__LINE__);
              goto Error;
            }
            ref.format(frm);
            dt_in = toc(&inner_clock);
            toc(&outer_clock);
            CHKJMP(d->_scanner2d._daq.waitForDone(SCANNER2D_DEFAULT_TIMEOUT));
            d->_scanner2d._daq.stopCLK();
            debug("Generating AO for z = %f."ENDL,z_um);
            d->generateAORampZ((float)z_um);
            d->writeAO();
            ++i;
          }

          status = 0;
          DBG("Scanner - Stack Acquisition task completed normally."ENDL);
Finalize:
          d->_scanner2d._shutter.Shut();
          d->_zpiezo.moveTo(ummin); // reset to starting position
          free(frm);
          free(wfm);
          Chan_Close(qdata);
          Chan_Close(qwfm);
          niscope_debug_print_status(vi);
          CHKERR(d->_scanner2d._daq.stopAO());
          CHKERR(d->_scanner2d._daq.stopCLK());
          DIGERR(niScope_Abort(vi));
          return status;
Error:
          warning("Error occurred during ScanStack<%s> task."ENDL,TypeStr<TPixel>());
          d->_scanner2d._daq.stopAO();
          d->_scanner2d._daq.stopCLK();
          goto Finalize;
        }

        template<class TPixel>
        unsigned int fetch::task::scanner::ScanStack<TPixel>::run_simulated( device::Scanner3D *d )
        {
          Chan *qdata = Chan_Open(d->_out->contents[0],CHAN_WRITE);
          Frame *frm   = NULL;
          device::SimulatedDigitizer *dig = d->_scanner2d._digitizer._simulated;
          Frame_With_Interleaved_Planes ref(
            dig->get_config().width(),
            d->_scanner2d.get_config().nscans()*2,
            3,TypeID<TPixel>());
          size_t nbytes;
          int status = 1; // status == 0 implies success, error otherwise
          f64 z_um,ummax,ummin,umstep;

          nbytes = ref.size_bytes();
          Chan_Resize(qdata, nbytes);
          frm = (Frame*)Chan_Token_Buffer_Alloc(qdata);
          ref.format(frm);

          debug("Simulated Stack!"ENDL);
          HERE;
          d->_zpiezo.getScanRange(&ummin,&ummax,&umstep);
          for(z_um=ummin+umstep;z_um<ummax && !d->_agent->is_stopping();z_um+=umstep)
          //for(int d=0;d<100;++d)
          { size_t pitch[4];
            size_t n[3];
            frm->compute_pitches(pitch);
            frm->get_shape(n);

            //Fill frame w random colors.
            { TPixel *c,*e;
              const f32 low = TypeMin<TPixel>(),
                       high = TypeMax<TPixel>(),
                        ptp = high - low,
                        rmx = RAND_MAX;
              c=e=(TPixel*)frm->data;
              e+=pitch[0]/pitch[3];
              for(;c<e;++c)
                *c = (TPixel) ((ptp*rand()/(float)RAND_MAX) + low);
            }

            if(CHAN_FAILURE( SCANNER_PUSH(qdata,(void**)&frm,nbytes) ))
            { warning("Scanner output frame queue overflowed."ENDL"\tAborting acquisition task."ENDL);
              goto Error;
            }
            ref.format(frm);
            DBG("Task: ScanStack<%s>: pushing frame"ENDL,TypeStr<TPixel>());
          }
          HERE;
Finalize:
          Chan_Close(qdata);
          free( frm );
          return status; // status == 0 implies success, error otherwise
Error:
          warning("Error occurred during ScanStack<%s> task."ENDL,TypeStr<TPixel>());
          goto Finalize;
        }

        template<class TPixel>
        unsigned int fetch::task::scanner::ScanStack<TPixel>::run_alazar( device::Scanner3D *d )
        { Chan *qdata = Chan_Open(d->_out->contents[0],CHAN_WRITE);
          Chan_Close(qdata);
          warning("Implement me!"ENDL);
          return 1;
        }
    }
  }
}
<commit_msg>Fix deadlock: added transaction locks in StackAcquistion task<commit_after>/*
 * StackAcquisition.cpp
 *
 *  Created on: May 10, 2010
 *      Author: Nathan Clack <clackn@janelia.hhmi.org>
 */
/*
 * Copyright 2010 Howard Hughes Medical Institute.
 * All rights reserved.
 * Use is subject to Janelia Farm Research Campus Software Copyright 1.1
 * license terms (http://license.janelia.org/license/jfrc_copyright_1_1.html).
 */

#include "common.h"
#include "StackAcquisition.h"
#include "Video.h"
#include "frame.h"
#include "devices\digitizer.h"
#include "devices\Microscope.h"

#if 0
#define DBG(...) debug(__VA_ARGS__);
#else
#define DBG(...)
#endif

#define DIGWRN( expr )  (niscope_chk( vi, expr, #expr, __FILE__, __LINE__, warning ))
#define DIGERR( expr )  (niscope_chk( vi, expr, #expr, __FILE__, __LINE__, error   ))
#define DIGJMP( expr )  goto_if_fail(VI_SUCCESS == niscope_chk( vi, expr, #expr, __FILE__, __LINE__, warning ), Error)
#define DAQWRN( expr )  (Guarded_DAQmx( (expr), #expr, __FILE__, __LINE__, warning))
#define DAQERR( expr )  (Guarded_DAQmx( (expr), #expr, __FILE__, __LINE__, error  ))
#define DAQJMP( expr )  goto_if_fail( 0==DAQWRN(expr), Error)

#define CHKERR( expr )  if(expr) {error("%s(%d)"ENDL"\tExpression indicated failure:"ENDL"\t%s"ENDL,__FILE__,__LINE__,#expr);} //( (expr), #expr, error  ))
#define CHKJMP( expr )  goto_if((expr),Error)

#if 0
#define SCANNER_DEBUG_FAIL_WHEN_FULL
#else
#define SCANNER_DEBUG_WAIT_WHEN_FULL
#endif

#ifdef SCANNER_DEBUG_FAIL_WHEN_FULL
#define SCANNER_PUSH(...) Chan_Next_Try(__VA_ARGS__)
#elif defined(SCANNER_DEBUG_WAIT_WHEN_FULL)
#define SCANNER_PUSH(...) Chan_Next(__VA_ARGS__)
#else
#error("An overflow behavior for the scanner should be specified");
#endif

namespace fetch
{

  namespace task
  {

    //
    // StackAcquisition -  microscope task
    //

    namespace microscope {

      //Upcasting
      unsigned int StackAcquisition::config(IDevice *d) {return config(dynamic_cast<device::Microscope*>(d));}
      unsigned int StackAcquisition::run   (IDevice *d) {return run   (dynamic_cast<device::Microscope*>(d));}

      unsigned int StackAcquisition::config(device::Microscope *d)
      {
        static task::scanner::ScanStack<i16> grabstack;
        std::string filename;

        Guarded_Assert(d);

        //Assemble pipeline here
        IDevice *cur;
        cur = d->configPipeline();

        CHKJMP( !d->file_series.ensurePathExists() );

        d->file_series.inc();
        filename = d->stack_filename();
        IDevice::connect(&d->disk,0,cur,0);
        Guarded_Assert( d->disk.close()==0 );
        //Guarded_Assert( d->disk.open(filename,"w")==0);

        d->__scan_agent.arm(&grabstack,&d->scanner);                      // why was this arm_nowait?

        return 1; //success
Error:
        return 0; //failure
      }

      static int _handle_wait_for_result(DWORD result, const char *msg)
      {
          return_val_if( result == WAIT_OBJECT_0  , 0 );
          return_val_if( result == WAIT_OBJECT_0+1, 1 );
          Guarded_Assert_WinErr( result != WAIT_FAILED );
          if(result == WAIT_ABANDONED_0)
              warning("StackAcquisition: Wait 0 abandoned"ENDL"\t%s"ENDL, msg);
          if(result == WAIT_ABANDONED_0+1)
              warning("StackAcquisition: Wait 1 abandoned"ENDL"\t%s"ENDL, msg);

          if(result == WAIT_TIMEOUT)
              warning("StackAcquisition: Wait timeout"ENDL"\t%s"ENDL, msg);

          Guarded_Assert_WinErr( result != WAIT_FAILED );

          return -1;
      }

      unsigned int StackAcquisition::run(device::Microscope *dc)
      {
        std::string filename;
        unsigned int eflag = 0; // success

        Guarded_Assert(dc->__scan_agent.is_runnable());
        //Guarded_Assert(dc->__io_agent.is_running());

        dc->transaction_lock();
        filename = dc->stack_filename();
        dc->file_series.ensurePathExists();
        eflag |= dc->disk.open(filename,"w");
        if(eflag)
          return eflag;
        eflag |= dc->runPipeline();
        eflag |= dc->__scan_agent.run() != 1;

        //Chan_Wait_For_Writer_Count(dc->__scan_agent._owner->_out->contents[0],1);

        { HANDLE hs[] = {dc->__scan_agent._thread,
                         dc->__self_agent._notify_stop};
          DWORD res;
          int   t;

          // wait for scan to complete (or cancel)
          dc->transaction_unlock();
          res = WaitForMultipleObjects(2,hs,FALSE,INFINITE);
          dc->transaction_lock();
          t = _handle_wait_for_result(res,"StackAcquisition::run - Wait for scanner to finish.");
          switch(t)
          { case 0:       // in this case, the scanner thread stopped.  Nothing left to do.
              eflag |= 0; // success
              //break;
            case 1:       // in this case, the stop event triggered and must be propagated.
              eflag |= dc->__scan_agent.stop(SCANNER2D_DEFAULT_TIMEOUT) != 1;
              break;
            default:      // in this case, there was a timeout or abandoned wait
              eflag |= 1; //failure
          }
        }

        // Output metadata and Increment file
        eflag |= dc->disk.close();
        dc->write_stack_metadata();
        dc->file_series.inc();
        //dc->connect(&dc->disk,0,dc->pipelineEnd(),0);

        eflag |= dc->stopPipeline(); // wait till the  pipeline stops
        dc->transaction_unlock();
        return eflag;
      }

    }  // namespace microscope

    //
    // ScanStack - scanner task
    //

    namespace scanner
    {

      template class ScanStack<i8 >;
      template class ScanStack<i16>;

      // upcasts
      template<class TPixel> unsigned int ScanStack<TPixel>::config (IDevice *d) {return config(dynamic_cast<device::Scanner3D*>(d));}
      template<class TPixel> unsigned int ScanStack<TPixel>::update (IDevice *d) {return update(dynamic_cast<device::Scanner3D*>(d));}

      template<class TPixel> unsigned int ScanStack<TPixel>::run    (IDevice *d)
      {
        device::Scanner3D *s = dynamic_cast<device::Scanner3D*>(d);
        device::Digitizer::Config digcfg = s->_scanner2d._digitizer.get_config();
        switch(digcfg.kind())
        {
        case cfg::device::Digitizer_DigitizerType_NIScope:
          return run_niscope(s);
          break;
        case cfg::device::Digitizer_DigitizerType_Alazar:
          return run_alazar(s);
          break;
        case cfg::device::Digitizer_DigitizerType_Simulated:
          return run_simulated(s);
          break;
        default:
          warning("ScanStack<>::run() - Got invalid kind() for Digitizer.get_config"ENDL);
        }
        return 0; //failure
      }

      template<class TPixel>
        unsigned int
        ScanStack<TPixel>::
        config(device::Scanner3D *d)
        {
          d->onConfigTask();
          debug("Scanner3D configured for StackAcquisition<%s>"ENDL, TypeStr<TPixel> ());
          return 1; //success
        }

      template<class TPixel>
        unsigned int
        ScanStack<TPixel>::
        update(device::Scanner3D *scanner)
        {
          scanner->generateAO();
          return 1;
        }

      template<class TPixel>
        unsigned int
        ScanStack<TPixel>::run_niscope(device::Scanner3D *d)
        {
          Chan *qdata = Chan_Open(d->_out->contents[0],CHAN_WRITE),
               *qwfm  = Chan_Open(d->_out->contents[1],CHAN_WRITE);
          Frame *frm = NULL;
          Frame_With_Interleaved_Lines ref;
          struct niScope_wfmInfo *wfm = NULL;
          ViInt32 nwfm;
          ViInt32 width;
          int i = 0, status = 1; // status == 0 implies success, error otherwise
          size_t nbytes, nbytes_info;
          f64 z_um,ummax,ummin,umstep;

          TicTocTimer outer_clock = tic(), inner_clock = tic();
          double dt_in = 0.0, dt_out = 0.0;

          device::NIScopeDigitizer *dig = d->_scanner2d._digitizer._niscope;
          device::NIScopeDigitizer::Config digcfg = dig->get_config();

          ViSession vi = dig->_vi;
          ViChar *chan = const_cast<ViChar*>(digcfg.chan_names().c_str());

          ref = _describe_actual_frame_niscope<TPixel>(
            dig,                                 // NISCope Digitizer
            d->_scanner2d.get_config().nscans(), // number of scans
            &width,                              // width in pixels (queried from board)
            &nwfm);                              // this should be the number of scans (queried from board)
          nbytes = ref.size_bytes();
          nbytes_info = nwfm * sizeof(struct niScope_wfmInfo);
          //
          Chan_Resize(qdata, nbytes);
          Chan_Resize(qwfm, nbytes_info);
          frm = (Frame*) Chan_Token_Buffer_Alloc(qdata);
          wfm = (struct niScope_wfmInfo*) Chan_Token_Buffer_Alloc(qwfm);
          nbytes = Chan_Buffer_Size_Bytes(qdata);
          nbytes_info = Chan_Buffer_Size_Bytes(qwfm);
          //
          ref.format(frm);

          d->_zpiezo.getScanRange(&ummin,&ummax,&umstep);
          d->_zpiezo.moveTo(ummin); // reset to starting position

          d->generateAORampZ((float)ummin);
          d->writeAO();
          d->_scanner2d._shutter.Open();
          CHKJMP(d->_scanner2d._daq.startAO());
          for(z_um=ummin+umstep;z_um<=ummax && !d->_agent->is_stopping();z_um+=umstep)
          {
            CHKJMP(d->_scanner2d._daq.startCLK());
            DIGJMP(niScope_InitiateAcquisition(vi));

            dt_out = toc(&outer_clock);
            toc(&inner_clock);
#if 1
            DIGJMP(Fetch<TPixel> (vi, chan, SCANNER_STACKACQ_TASK_FETCH_TIMEOUT,//10.0, //(-1=infinite) (0.0=immediate) // seconds
                                  width,
                                  (TPixel*) frm->data,
                                  wfm));
#endif

            // Push the acquired data down the output pipes
            DBG("Task: StackAcquisition<%s>: pushing wfm"ENDL, TypeStr<TPixel> ());
            Chan_Next_Try(qwfm,(void**)&wfm,nbytes_info);
            DBG("Task: StackAcquisition<%s>: pushing frame"ENDL, TypeStr<TPixel> ());
            if(CHAN_FAILURE( SCANNER_PUSH(qdata,(void**)&frm,nbytes) ))
            { warning("(%s:%d) Scanner output frame queue overflowed."ENDL"\tAborting stack acquisition task."ENDL,__FILE__,__LINE__);
              goto Error;
            }
            ref.format(frm);
            dt_in = toc(&inner_clock);
            toc(&outer_clock);
            CHKJMP(d->_scanner2d._daq.waitForDone(SCANNER2D_DEFAULT_TIMEOUT));
            d->_scanner2d._daq.stopCLK();
            debug("Generating AO for z = %f."ENDL,z_um);
            d->generateAORampZ((float)z_um);
            d->writeAO();
            ++i;
          }

          status = 0;
          DBG("Scanner - Stack Acquisition task completed normally."ENDL);
Finalize:
          d->_scanner2d._shutter.Shut();
          d->_zpiezo.moveTo(ummin); // reset to starting position
          free(frm);
          free(wfm);
          Chan_Close(qdata);
          Chan_Close(qwfm);
          niscope_debug_print_status(vi);
          CHKERR(d->_scanner2d._daq.stopAO());
          CHKERR(d->_scanner2d._daq.stopCLK());
          DIGERR(niScope_Abort(vi));
          return status;
Error:
          warning("Error occurred during ScanStack<%s> task."ENDL,TypeStr<TPixel>());
          d->_scanner2d._daq.stopAO();
          d->_scanner2d._daq.stopCLK();
          goto Finalize;
        }

        template<class TPixel>
        unsigned int fetch::task::scanner::ScanStack<TPixel>::run_simulated( device::Scanner3D *d )
        {
          Chan *qdata = Chan_Open(d->_out->contents[0],CHAN_WRITE);
          Frame *frm   = NULL;
          device::SimulatedDigitizer *dig = d->_scanner2d._digitizer._simulated;
          Frame_With_Interleaved_Planes ref(
            dig->get_config().width(),
            d->_scanner2d.get_config().nscans()*2,
            3,TypeID<TPixel>());
          size_t nbytes;
          int status = 1; // status == 0 implies success, error otherwise
          f64 z_um,ummax,ummin,umstep;

          nbytes = ref.size_bytes();
          Chan_Resize(qdata, nbytes);
          frm = (Frame*)Chan_Token_Buffer_Alloc(qdata);
          ref.format(frm);

          debug("Simulated Stack!"ENDL);
          HERE;
          d->_zpiezo.getScanRange(&ummin,&ummax,&umstep);
          for(z_um=ummin+umstep;z_um<ummax && !d->_agent->is_stopping();z_um+=umstep)
          //for(int d=0;d<100;++d)
          { size_t pitch[4];
            size_t n[3];
            frm->compute_pitches(pitch);
            frm->get_shape(n);

            //Fill frame w random colors.
            { TPixel *c,*e;
              const f32 low = TypeMin<TPixel>(),
                       high = TypeMax<TPixel>(),
                        ptp = high - low,
                        rmx = RAND_MAX;
              c=e=(TPixel*)frm->data;
              e+=pitch[0]/pitch[3];
              for(;c<e;++c)
                *c = (TPixel) ((ptp*rand()/(float)RAND_MAX) + low);
            }

            if(CHAN_FAILURE( SCANNER_PUSH(qdata,(void**)&frm,nbytes) ))
            { warning("Scanner output frame queue overflowed."ENDL"\tAborting acquisition task."ENDL);
              goto Error;
            }
            ref.format(frm);
            DBG("Task: ScanStack<%s>: pushing frame"ENDL,TypeStr<TPixel>());
          }
          HERE;
Finalize:
          Chan_Close(qdata);
          free( frm );
          return status; // status == 0 implies success, error otherwise
Error:
          warning("Error occurred during ScanStack<%s> task."ENDL,TypeStr<TPixel>());
          goto Finalize;
        }

        template<class TPixel>
        unsigned int fetch::task::scanner::ScanStack<TPixel>::run_alazar( device::Scanner3D *d )
        { Chan *qdata = Chan_Open(d->_out->contents[0],CHAN_WRITE);
          Chan_Close(qdata);
          warning("Implement me!"ENDL);
          return 1;
        }
    }
  }
}
<|endoftext|>


<commit_before>#ifndef LTL_TASK_QUEUE_HPP
#define LTL_TASK_QUEUE_HPP

#include <functional>
#include <memory>
#include <type_traits>

#include "ltl/future.hpp"
#include "ltl/promise.hpp"
#include "ltl/detail/task_queue_impl.hpp"
#include "ltl/detail/current_task_context.hpp"
#include "ltl/detail/wrapped_function.hpp"

namespace ltl {

class task_queue
{
public:
    explicit task_queue(char const* name = nullptr)
    : impl_(std::make_shared<detail::task_queue_impl>(name))
    {
    }

    task_queue(task_queue const&) =delete;
    task_queue& operator=(task_queue const&) =delete;

    void join()
    {
        impl_->join();
    }

    void enqueue(std::function<void()> task)
    {
        impl_->enqueue_resumable(std::move(task));
    }

    template <typename Function>
    future<typename std::result_of<Function()>::type> execute(Function&& task);

private:
    std::shared_ptr<detail::task_queue_impl> const impl_;
};

template <typename Function>
inline future<typename std::result_of<Function()>::type> task_queue::execute(Function&& task)
{
    typedef typename std::result_of<Function()>::type result_type;
    detail::wrapped_function<result_type> wf(current_task_context::get()->get_task_queue()->shared_from_this(),
                                             std::forward<Function>(task));
    impl_->enqueue_resumable(wf);
    return wf.promise_->get_future();
}

template <typename Function, typename... Args>
future<typename std::result_of<Function(Args const&...)>::type> async(task_queue& tq, Function&& f, Args const&... args)
{
    return tq.execute([=](){
        return f(args...);
    });
}

template <typename Function>
future<typename std::result_of<Function()>::type> operator <<= (task_queue& tq, Function&& f)
{
    return async(tq, std::forward<Function>(f));
}

} // namespace ltl

#endif // LTL_TASK_QUEUE_HPP
<commit_msg>task_queue is not moveable<commit_after>#ifndef LTL_TASK_QUEUE_HPP
#define LTL_TASK_QUEUE_HPP

#include <functional>
#include <memory>
#include <type_traits>

#include "ltl/future.hpp"
#include "ltl/promise.hpp"
#include "ltl/detail/task_queue_impl.hpp"
#include "ltl/detail/current_task_context.hpp"
#include "ltl/detail/wrapped_function.hpp"

namespace ltl {

class task_queue
{
public:
    explicit task_queue(char const* name = nullptr)
    : impl_(std::make_shared<detail::task_queue_impl>(name))
    {
    }

    task_queue(task_queue const&) =delete;
    task_queue& operator=(task_queue const&) =delete;

    task_queue(task_queue&& other)
    : impl_(std::move(other.impl_))
    {
    }

    task_queue& operator=(task_queue&& other)
    {
        impl_ = std::move(other.impl_);
        return *this;
    }

    void join()
    {
        impl_->join();
    }

    void enqueue(std::function<void()> task)
    {
        impl_->enqueue_resumable(std::move(task));
    }

    template <typename Function>
    future<typename std::result_of<Function()>::type> execute(Function&& task);

private:
    std::shared_ptr<detail::task_queue_impl> impl_;
};

template <typename Function>
inline future<typename std::result_of<Function()>::type> task_queue::execute(Function&& task)
{
    typedef typename std::result_of<Function()>::type result_type;
    detail::wrapped_function<result_type> wf(current_task_context::get()->get_task_queue()->shared_from_this(),
                                             std::forward<Function>(task));
    impl_->enqueue_resumable(wf);
    return wf.promise_->get_future();
}

template <typename Function, typename... Args>
future<typename std::result_of<Function(Args const&...)>::type> async(task_queue& tq, Function&& f, Args const&... args)
{
    return tq.execute([=](){
        return f(args...);
    });
}

template <typename Function>
future<typename std::result_of<Function()>::type> operator <<= (task_queue& tq, Function&& f)
{
    return async(tq, std::forward<Function>(f));
}

} // namespace ltl

#endif // LTL_TASK_QUEUE_HPP
<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
//  Copyright (c) 2009-2013, United States Government as represented by the
//  Administrator of the National Aeronautics and Space Administration. All
//  rights reserved.
//
//  The NGT platform is licensed under the Apache License, Version 2.0 (the
//  "License"); you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// __END_LICENSE__

/// \file orbitviz.cc
///

// This is as scaled-down version of orbitviz that only operates on pinhole files

/************************************************************************
 *     File: orbitviz.cc
 ************************************************************************/
#include <vw/Core.h>
#include <vw/Math.h>
#include <vw/FileIO/KML.h>
#include <vw/FileIO/FileUtils.h>
#include <vw/Camera.h>
#include <vw/Cartography.h>

#include <iomanip>

#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/fstream.hpp>

#include <asp/Core/Common.h>

using namespace vw;
using namespace vw::camera;
using namespace vw::cartography;
namespace po = boost::program_options;
namespace fs = boost::filesystem;

struct Options : public vw::cartography::GdalWriteOptions {
  Options() {}
  // Input
  std::vector<std::string> input_files;
  std::string path_to_outside_model;

  // Settings
  bool write_csv, hide_labels;
  double model_scale; ///< Size scaling applied to 3D models

  // Output
  std::string out_file;
};

/// Strip the directory out of a file path
std::string strip_directory( std::string const& input){
 boost::filesystem::path p(input);
 return p.filename().string();
}

/// Strip the directory and extension out of a file path
std::string strip_directory_and_extension( std::string const& input){
 boost::filesystem::path p(input);
 return p.stem().string();
}

// Would be nice to have this in a function
/// Populate a list of all files in a directory.
/// - Returns the number of files found.
/// - If an extension is passed in, files must match the extension.
size_t get_files_in_folder(std::string              const& folder,
                           std::vector<std::string>      & output,
                           std::string              const& ext="")
{
  output.clear();

  // Handle invalid inputs
  if(!boost::filesystem::exists(folder) || !boost::filesystem::is_directory(folder))
    return 0;

  boost::filesystem::directory_iterator it(folder);
  boost::filesystem::directory_iterator endit;

  if (ext != ""){ // Check the extension
    while(it != endit) {
        if(boost::filesystem::is_regular_file(*it) && it->path().extension() == ext)
          output.push_back(it->path().filename().string());
        ++it;
    }
  }
  else{ // No extension check
    while(it != endit) {
        if(boost::filesystem::is_regular_file(*it))
          output.push_back(it->path().filename().string());
        ++it;
    }
  }
  return output.size();
}

void handle_arguments( int argc, char *argv[], Options& opt ) {
  po::options_description general_options("");
  general_options.add_options()
    ("output,o",                po::value(&opt.out_file)->default_value("orbit.kml"),
          "The output kml file that will be written")
    ("use-path-to-dae-model,u", po::value(&opt.path_to_outside_model),
          "Instead of using an icon to mark a camera, use a 3D model with extension .dae")
    ("hide-labels",             po::bool_switch(&opt.hide_labels)->default_value(false)->implicit_value(true),
          "Hide image names unless the camera is highlighted.")
    // The KML class applies a model scale of 3000 * this value.
    ("model-scale",             po::value(&opt.model_scale)->default_value(1.0/30.0),
          "Scale factor applied to 3D model size.")
    ("write-csv", po::bool_switch(&opt.write_csv)->default_value(false),
     "Write a csv file with the orbital data.");
  general_options.add( vw::cartography::GdalWriteOptionsDescription(opt) );

  po::options_description positional("");
  positional.add_options()
    ("input-files", po::value(&opt.input_files) );

  po::positional_options_description positional_desc;
  positional_desc.add("input-files", -1);

  std::string usage("[options] <input cameras>\n");

  bool allow_unregistered = false;
  std::vector<std::string> unregistered;
  po::variables_map vm =
    asp::check_command_line( argc, argv, opt, general_options, general_options,
                             positional, positional_desc, usage,
                             allow_unregistered, unregistered );

 if (opt.input_files.empty())
  vw_throw( ArgumentErr() << "No input files provided!\n" );

}

int main(int argc, char* argv[]) {

  Options opt;
  //try {
  handle_arguments( argc, argv, opt );

  size_t num_cameras = opt.input_files.size();

  // Prepare output directory
  vw::create_out_dir(opt.out_file);

  // Create the KML file.
  KMLFile kml( opt.out_file, "orbitviz" );

  // Style listing
  if ( opt.path_to_outside_model.empty() ) {
    // Placemark Style
    kml.append_style( "plane", "", 1.2,
                      "http://maps.google.com/mapfiles/kml/shapes/airports.png",
                      opt.hide_labels);
    kml.append_style( "plane_highlight", "", 1.4,
                      "http://maps.google.com/mapfiles/kml/shapes/airports.png");
    kml.append_stylemap( "camera_placemark", "plane",
                         "plane_highlight" );
  }

  // Load up the datum
  cartography::Datum datum("WGS84");

  std::string csv_file = fs::path(opt.out_file).replace_extension("csv").string();
  std::ofstream csv_handle;
  if ( opt.write_csv ) {
    csv_handle.open(csv_file.c_str());

    if ( !csv_handle.is_open() )
      vw_throw( IOErr() << "Unable to open output file.\n" );
  }

  Vector2 camera_pixel(0, 0);

  // Building Camera Models and then writing to KML
  std::vector<Vector3> camera_positions(num_cameras);
  for (size_t i=0; i < num_cameras; i++) {
    // Load this input file
    PinholeModel current_camera(opt.input_files[i]);

    if ( opt.write_csv ) {
      csv_handle << opt.input_files[i] << ", ";

      Vector3 xyz = current_camera.camera_center(camera_pixel);
      csv_handle << std::setprecision(12);
      csv_handle << xyz[0] << ", "
                 << xyz[1] << ", " << xyz[2] << "\n";
    } // End csv write condition

    // Compute and record the GDC coordinates
    Vector3 lon_lat_alt = datum.cartesian_to_geodetic(
                              current_camera.camera_center(camera_pixel));
    camera_positions[i] = lon_lat_alt;

    // Adding Placemarks
    std::string display_name = strip_directory(opt.input_files[i]);
    if (!opt.path_to_outside_model.empty()) {
      kml.append_model( opt.path_to_outside_model,
                        lon_lat_alt.x(), lon_lat_alt.y(),
                        inverse(current_camera.camera_pose(camera_pixel)),
                        display_name, "",
                        lon_lat_alt[2], opt.model_scale );
    } else {
      kml.append_placemark( lon_lat_alt.x(), lon_lat_alt.y(),
                            display_name, "", "camera_placemark",
                            lon_lat_alt[2], true );
    }

  } // End loop through cameras

  // Put the Writing: messages here, so that they show up after all other info.
  vw_out() << "Writing: " << opt.out_file << std::endl;
  kml.close_kml();

  if (opt.write_csv){
    vw_out() << "Writing: " << csv_file << std::endl;
    csv_handle.close();
  }

  //} ASP_STANDARD_CATCHES;

  return 0;
}
<commit_msg>Added input file option to orbitviz_pinhole<commit_after>// __BEGIN_LICENSE__
//  Copyright (c) 2009-2013, United States Government as represented by the
//  Administrator of the National Aeronautics and Space Administration. All
//  rights reserved.
//
//  The NGT platform is licensed under the Apache License, Version 2.0 (the
//  "License"); you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// __END_LICENSE__

/// \file orbitviz.cc
///

// This is as scaled-down version of orbitviz that only operates on pinhole files

/************************************************************************
 *     File: orbitviz.cc
 ************************************************************************/
#include <vw/Core.h>
#include <vw/Math.h>
#include <vw/FileIO/KML.h>
#include <vw/FileIO/FileUtils.h>
#include <vw/Camera.h>
#include <vw/Cartography.h>

#include <iomanip>

#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/fstream.hpp>

#include <asp/Core/Common.h>

using namespace vw;
using namespace vw::camera;
using namespace vw::cartography;
namespace po = boost::program_options;
namespace fs = boost::filesystem;

struct Options : public vw::cartography::GdalWriteOptions {
  Options() {}
  // Input
  std::vector<std::string> input_files;
  std::string path_to_outside_model, input_list;

  // Settings
  bool write_csv, hide_labels;
  double model_scale; ///< Size scaling applied to 3D models

  // Output
  std::string out_file;
};

/// Strip the directory out of a file path
std::string strip_directory( std::string const& input){
 boost::filesystem::path p(input);
 return p.filename().string();
}

/// Strip the directory and extension out of a file path
std::string strip_directory_and_extension( std::string const& input){
 boost::filesystem::path p(input);
 return p.stem().string();
}

// Would be nice to have this in a function
/// Populate a list of all files in a directory.
/// - Returns the number of files found.
/// - If an extension is passed in, files must match the extension.
size_t get_files_in_folder(std::string              const& folder,
                           std::vector<std::string>      & output,
                           std::string              const& ext="")
{
  output.clear();

  // Handle invalid inputs
  if(!boost::filesystem::exists(folder) || !boost::filesystem::is_directory(folder))
    return 0;

  boost::filesystem::directory_iterator it(folder);
  boost::filesystem::directory_iterator endit;

  if (ext != ""){ // Check the extension
    while(it != endit) {
        if(boost::filesystem::is_regular_file(*it) && it->path().extension() == ext)
          output.push_back(it->path().filename().string());
        ++it;
    }
  }
  else{ // No extension check
    while(it != endit) {
        if(boost::filesystem::is_regular_file(*it))
          output.push_back(it->path().filename().string());
        ++it;
    }
  }
  return output.size();
}

void handle_arguments( int argc, char *argv[], Options& opt ) {
  po::options_description general_options("");
  general_options.add_options()
    ("output,o",                po::value(&opt.out_file)->default_value("orbit.kml"),
          "The output kml file that will be written")
    ("input-list", po::value(&opt.input_list)->default_value(""),
          "File containing list of input files")
    ("use-path-to-dae-model,u", po::value(&opt.path_to_outside_model),
          "Instead of using an icon to mark a camera, use a 3D model with extension .dae")
    ("hide-labels",             po::bool_switch(&opt.hide_labels)->default_value(false)->implicit_value(true),
          "Hide image names unless the camera is highlighted.")
    // The KML class applies a model scale of 3000 * this value.
    ("model-scale",             po::value(&opt.model_scale)->default_value(1.0/30.0),
          "Scale factor applied to 3D model size.")
    ("write-csv", po::bool_switch(&opt.write_csv)->default_value(false),
     "Write a csv file with the orbital data.");
  general_options.add( vw::cartography::GdalWriteOptionsDescription(opt) );

  po::options_description positional("");
  positional.add_options()
    ("input-files", po::value(&opt.input_files) );

  po::positional_options_description positional_desc;
  positional_desc.add("input-files", -1);

  std::string usage("[options] <input cameras>\n");

  bool allow_unregistered = false;
  std::vector<std::string> unregistered;
  po::variables_map vm =
    asp::check_command_line( argc, argv, opt, general_options, general_options,
                             positional, positional_desc, usage,
                             allow_unregistered, unregistered );

 if (opt.input_list != "") {
   std::ifstream handle(opt.input_list.c_str());
   std::string line;
   size_t count = 0;
   while (getline(handle, line)){
     opt.input_files.push_back(line);
     ++count;
   }
   handle.close();
   vw_out() << "Read in " << count << " camera files from " << opt.input_list << std::endl;
 }

 if (opt.input_files.empty())
  vw_throw( ArgumentErr() << "No input files provided!\n" );

}

int main(int argc, char* argv[]) {

  Options opt;
  //try {
  handle_arguments( argc, argv, opt );

  size_t num_cameras = opt.input_files.size();

  // Prepare output directory
  vw::create_out_dir(opt.out_file);

  // Create the KML file.
  KMLFile kml( opt.out_file, "orbitviz" );

  // Style listing
  if ( opt.path_to_outside_model.empty() ) {
    // Placemark Style
    kml.append_style( "plane", "", 1.2,
                      "http://maps.google.com/mapfiles/kml/shapes/airports.png",
                      opt.hide_labels);
    kml.append_style( "plane_highlight", "", 1.4,
                      "http://maps.google.com/mapfiles/kml/shapes/airports.png");
    kml.append_stylemap( "camera_placemark", "plane",
                         "plane_highlight" );
  }

  // Load up the datum
  cartography::Datum datum("WGS84");

  std::string csv_file = fs::path(opt.out_file).replace_extension("csv").string();
  std::ofstream csv_handle;
  if ( opt.write_csv ) {
    csv_handle.open(csv_file.c_str());

    if ( !csv_handle.is_open() )
      vw_throw( IOErr() << "Unable to open output file.\n" );
  }

  Vector2 camera_pixel(0, 0);

  // Building Camera Models and then writing to KML
  std::vector<Vector3> camera_positions(num_cameras);
  for (size_t i=0; i < num_cameras; i++) {
    // Load this input file
    PinholeModel current_camera(opt.input_files[i]);

    if ( opt.write_csv ) {
      csv_handle << opt.input_files[i] << ", ";

      Vector3 xyz = current_camera.camera_center(camera_pixel);
      csv_handle << std::setprecision(12);
      csv_handle << xyz[0] << ", "
                 << xyz[1] << ", " << xyz[2] << "\n";
    } // End csv write condition

    // Compute and record the GDC coordinates
    Vector3 lon_lat_alt = datum.cartesian_to_geodetic(
                              current_camera.camera_center(camera_pixel));
    camera_positions[i] = lon_lat_alt;

    // Adding Placemarks
    std::string display_name = strip_directory(opt.input_files[i]);
    if (!opt.path_to_outside_model.empty()) {
      kml.append_model( opt.path_to_outside_model,
                        lon_lat_alt.x(), lon_lat_alt.y(),
                        inverse(current_camera.camera_pose(camera_pixel)),
                        display_name, "",
                        lon_lat_alt[2], opt.model_scale );
    } else {
      kml.append_placemark( lon_lat_alt.x(), lon_lat_alt.y(),
                            display_name, "", "camera_placemark",
                            lon_lat_alt[2], true );
    }

  } // End loop through cameras

  // Put the Writing: messages here, so that they show up after all other info.
  vw_out() << "Writing: " << opt.out_file << std::endl;
  kml.close_kml();

  if (opt.write_csv){
    vw_out() << "Writing: " << csv_file << std::endl;
    csv_handle.close();
  }

  //} ASP_STANDARD_CATCHES;

  return 0;
}
<|endoftext|>


<commit_before>#include <StdAfx.h>
#include <UI/ViewPane/SplitterPane.h>

namespace viewpane
{
	SplitterPane* SplitterPane::CreateVerticalPane(const int paneID, const UINT uidLabel)
	{
		const auto pane = CreateHorizontalPane(paneID, uidLabel);
		pane->m_bVertical = true;

		return pane;
	}

	SplitterPane* SplitterPane::CreateHorizontalPane(const int paneID, const UINT uidLabel)
	{
		const auto pane = new (std::nothrow) SplitterPane();
		pane->SetLabel(uidLabel);
		if (uidLabel)
		{
			pane->m_bCollapsible = true;
		}

		pane->m_paneID = paneID;
		return pane;
	}

	int SplitterPane::GetMinWidth(_In_ HDC hdc)
	{
		(void) ViewPane::GetMinWidth(hdc);
		if (m_bVertical)
		{
			return max(m_PaneOne->GetMinWidth(hdc), m_PaneTwo->GetMinWidth(hdc));
		}
		else
		{
			return m_PaneOne->GetMinWidth(hdc) + m_PaneTwo->GetMinWidth(hdc) + m_lpSplitter
					   ? m_lpSplitter->GetSplitWidth()
					   : 0;
		}
	}

	int SplitterPane::GetFixedHeight()
	{
		auto iHeight = 0;
		// TODO: Better way to find the top pane
		if (0 != m_paneID) iHeight += m_iSmallHeightMargin; // Top margin

		if (m_bCollapsible)
		{
			// Our expand/collapse button
			iHeight += m_iButtonHeight;
		}

		// A small margin between our button and the splitter control, if we're collapsible and not collapsed
		if (!m_bCollapsed && m_bCollapsible)
		{
			iHeight += m_iSmallHeightMargin;
		}

		if (!m_bCollapsed)
		{
			if (m_bVertical)
			{
				iHeight += m_PaneOne->GetFixedHeight() + m_PaneTwo->GetFixedHeight() +
						   (m_lpSplitter ? m_lpSplitter->GetSplitWidth() : 0);
			}
			else
			{
				iHeight += max(m_PaneOne->GetFixedHeight(), m_PaneTwo->GetFixedHeight());
			}
		}

		iHeight += m_iSmallHeightMargin; // Bottom margin

		return iHeight;
	}

	int SplitterPane::GetLines()
	{
		if (!m_bCollapsed)
		{
			if (m_bVertical)
			{
				return m_PaneOne->GetLines() + m_PaneTwo->GetLines();
			}
			else
			{
				return max(m_PaneOne->GetLines(), m_PaneTwo->GetLines());
			}
		}

		return 0;
	}

	ULONG SplitterPane::HandleChange(const UINT nID)
	{
		// See if the panes can handle the change first
		auto paneID = m_PaneOne->HandleChange(nID);
		if (paneID != static_cast<ULONG>(-1)) return paneID;

		paneID = m_PaneTwo->HandleChange(nID);
		if (paneID != static_cast<ULONG>(-1)) return paneID;

		return ViewPane::HandleChange(nID);
	}

	void SplitterPane::SetMargins(
		const int iMargin,
		const int iSideMargin,
		const int iLabelHeight, // Height of the label
		const int iSmallHeightMargin,
		const int iLargeHeightMargin,
		const int iButtonHeight, // Height of buttons below the control
		const int iEditHeight) // height of an edit control
	{
		ViewPane::SetMargins(
			iMargin, iSideMargin, iLabelHeight, iSmallHeightMargin, iLargeHeightMargin, iButtonHeight, iEditHeight);

		if (m_PaneOne)
		{
			m_PaneOne->SetMargins(
				iMargin, iSideMargin, iLabelHeight, iSmallHeightMargin, iLargeHeightMargin, iButtonHeight, iEditHeight);
		}

		if (m_PaneTwo)
		{
			m_PaneTwo->SetMargins(
				iMargin, iSideMargin, iLabelHeight, iSmallHeightMargin, iLargeHeightMargin, iButtonHeight, iEditHeight);
		}
	}

	void SplitterPane::Initialize(_In_ CWnd* pParent, _In_ HDC hdc)
	{
		ViewPane::Initialize(pParent, nullptr);

		m_lpSplitter = new controls::CFakeSplitter();

		if (m_lpSplitter)
		{
			m_lpSplitter->Init(pParent->GetSafeHwnd());
			m_lpSplitter->SetSplitType(m_bVertical ? controls::SplitVertical : controls::SplitHorizontal);
			m_PaneOne->Initialize(m_lpSplitter, hdc);
			m_PaneTwo->Initialize(m_lpSplitter, hdc);
			m_lpSplitter->SetPaneOne(m_PaneOne);
			m_lpSplitter->SetPaneTwo(m_PaneTwo);
		}

		m_bInitialized = true;
	}

	void SplitterPane::DeferWindowPos(
		_In_ HDWP hWinPosInfo,
		_In_ const int x,
		_In_ int y,
		_In_ const int width,
		_In_ int height)
	{
		output::DebugPrint(
			DBGDraw, L"SplitterPane::DeferWindowPos x:%d y:%d width:%d height: %d\n", x, y, width, height);

		if (0 != m_paneID)
		{
			y += m_iSmallHeightMargin;
			height -= m_iSmallHeightMargin;
		}

		ViewPane::DeferWindowPos(hWinPosInfo, x, y, width, height);

		if (m_bCollapsed)
		{
			EC_B_S(m_lpSplitter->ShowWindow(SW_HIDE));
		}
		else
		{
			if (m_bCollapsible)
			{
				y += m_iLabelHeight + m_iSmallHeightMargin;
				height -= m_iLabelHeight + m_iSmallHeightMargin;
			}

			EC_B_S(m_lpSplitter->ShowWindow(SW_SHOW));
			::DeferWindowPos(hWinPosInfo, m_lpSplitter->GetSafeHwnd(), nullptr, x, y, width, height, SWP_NOZORDER);
			m_lpSplitter->OnSize(NULL, width, height);
		}
	}
} // namespace viewpane<commit_msg>Fix bottom margins on non collapsed splitter<commit_after>#include <StdAfx.h>
#include <UI/ViewPane/SplitterPane.h>

namespace viewpane
{
	SplitterPane* SplitterPane::CreateVerticalPane(const int paneID, const UINT uidLabel)
	{
		const auto pane = CreateHorizontalPane(paneID, uidLabel);
		pane->m_bVertical = true;

		return pane;
	}

	SplitterPane* SplitterPane::CreateHorizontalPane(const int paneID, const UINT uidLabel)
	{
		const auto pane = new (std::nothrow) SplitterPane();
		pane->SetLabel(uidLabel);
		if (uidLabel)
		{
			pane->m_bCollapsible = true;
		}

		pane->m_paneID = paneID;
		return pane;
	}

	int SplitterPane::GetMinWidth(_In_ HDC hdc)
	{
		(void) ViewPane::GetMinWidth(hdc);
		if (m_bVertical)
		{
			return max(m_PaneOne->GetMinWidth(hdc), m_PaneTwo->GetMinWidth(hdc));
		}
		else
		{
			return m_PaneOne->GetMinWidth(hdc) + m_PaneTwo->GetMinWidth(hdc) + m_lpSplitter
					   ? m_lpSplitter->GetSplitWidth()
					   : 0;
		}
	}

	int SplitterPane::GetFixedHeight()
	{
		auto iHeight = 0;
		// TODO: Better way to find the top pane
		if (0 != m_paneID) iHeight += m_iSmallHeightMargin; // Top margin

		if (m_bCollapsible)
		{
			// Our expand/collapse button
			iHeight += m_iButtonHeight;
		}

		// A small margin between our button and the splitter control, if we're collapsible and not collapsed
		if (!m_bCollapsed && m_bCollapsible)
		{
			iHeight += m_iSmallHeightMargin;
		}

		if (!m_bCollapsed)
		{
			if (m_bVertical)
			{
				iHeight += m_PaneOne->GetFixedHeight() + m_PaneTwo->GetFixedHeight() +
						   (m_lpSplitter ? m_lpSplitter->GetSplitWidth() : 0);
			}
			else
			{
				iHeight += max(m_PaneOne->GetFixedHeight(), m_PaneTwo->GetFixedHeight());
			}
		}

		if (m_bCollapsed)
		{
			iHeight += m_iSmallHeightMargin; // Bottom margin
		}

		return iHeight;
	}

	int SplitterPane::GetLines()
	{
		if (!m_bCollapsed)
		{
			if (m_bVertical)
			{
				return m_PaneOne->GetLines() + m_PaneTwo->GetLines();
			}
			else
			{
				return max(m_PaneOne->GetLines(), m_PaneTwo->GetLines());
			}
		}

		return 0;
	}

	ULONG SplitterPane::HandleChange(const UINT nID)
	{
		// See if the panes can handle the change first
		auto paneID = m_PaneOne->HandleChange(nID);
		if (paneID != static_cast<ULONG>(-1)) return paneID;

		paneID = m_PaneTwo->HandleChange(nID);
		if (paneID != static_cast<ULONG>(-1)) return paneID;

		return ViewPane::HandleChange(nID);
	}

	void SplitterPane::SetMargins(
		const int iMargin,
		const int iSideMargin,
		const int iLabelHeight, // Height of the label
		const int iSmallHeightMargin,
		const int iLargeHeightMargin,
		const int iButtonHeight, // Height of buttons below the control
		const int iEditHeight) // height of an edit control
	{
		ViewPane::SetMargins(
			iMargin, iSideMargin, iLabelHeight, iSmallHeightMargin, iLargeHeightMargin, iButtonHeight, iEditHeight);

		if (m_PaneOne)
		{
			m_PaneOne->SetMargins(
				iMargin, iSideMargin, iLabelHeight, iSmallHeightMargin, iLargeHeightMargin, iButtonHeight, iEditHeight);
		}

		if (m_PaneTwo)
		{
			m_PaneTwo->SetMargins(
				iMargin, iSideMargin, iLabelHeight, iSmallHeightMargin, iLargeHeightMargin, iButtonHeight, iEditHeight);
		}
	}

	void SplitterPane::Initialize(_In_ CWnd* pParent, _In_ HDC hdc)
	{
		ViewPane::Initialize(pParent, nullptr);

		m_lpSplitter = new controls::CFakeSplitter();

		if (m_lpSplitter)
		{
			m_lpSplitter->Init(pParent->GetSafeHwnd());
			m_lpSplitter->SetSplitType(m_bVertical ? controls::SplitVertical : controls::SplitHorizontal);
			m_PaneOne->Initialize(m_lpSplitter, hdc);
			m_PaneTwo->Initialize(m_lpSplitter, hdc);
			m_lpSplitter->SetPaneOne(m_PaneOne);
			m_lpSplitter->SetPaneTwo(m_PaneTwo);
		}

		m_bInitialized = true;
	}

	void SplitterPane::DeferWindowPos(
		_In_ HDWP hWinPosInfo,
		_In_ const int x,
		_In_ int y,
		_In_ const int width,
		_In_ int height)
	{
		output::DebugPrint(
			DBGDraw, L"SplitterPane::DeferWindowPos x:%d y:%d width:%d height: %d\n", x, y, width, height);

		if (0 != m_paneID)
		{
			y += m_iSmallHeightMargin;
			height -= m_iSmallHeightMargin;
		}

		ViewPane::DeferWindowPos(hWinPosInfo, x, y, width, height);

		if (m_bCollapsed)
		{
			EC_B_S(m_lpSplitter->ShowWindow(SW_HIDE));
		}
		else
		{
			if (m_bCollapsible)
			{
				y += m_iLabelHeight + m_iSmallHeightMargin;
				height -= m_iLabelHeight + m_iSmallHeightMargin;
			}

			EC_B_S(m_lpSplitter->ShowWindow(SW_SHOW));
			::DeferWindowPos(hWinPosInfo, m_lpSplitter->GetSafeHwnd(), nullptr, x, y, width, height, SWP_NOZORDER);
			m_lpSplitter->OnSize(NULL, width, height);
		}
	}
} // namespace viewpane<|endoftext|>