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

#include "field_index.h"
#include "ordered_field_index_inserter.h"
#include "posting_iterator.h"
#include <vespa/searchlib/bitcompression/posocccompression.h>
#include <vespa/searchlib/queryeval/booleanmatchiteratorwrapper.h>
#include <vespa/searchlib/queryeval/searchiterator.h>
#include <vespa/vespalib/btree/btree.hpp>
#include <vespa/vespalib/btree/btreeiterator.hpp>
#include <vespa/vespalib/btree/btreenode.hpp>
#include <vespa/vespalib/btree/btreenodeallocator.hpp>
#include <vespa/vespalib/btree/btreenodestore.hpp>
#include <vespa/vespalib/btree/btreeroot.hpp>
#include <vespa/vespalib/btree/btreestore.hpp>
#include <vespa/vespalib/util/array.hpp>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/stringfmt.h>

#include <vespa/log/log.h>
LOG_SETUP(".searchlib.memoryindex.field_index");

using search::fef::TermFieldMatchDataArray;
using search::index::DocIdAndFeatures;
using search::index::Schema;
using search::index::WordDocElementFeatures;
using search::queryeval::BooleanMatchIteratorWrapper;
using search::queryeval::FieldSpecBase;
using search::queryeval::SearchIterator;
using search::queryeval::SimpleLeafBlueprint;
using vespalib::GenerationHandler;

namespace search::memoryindex {

using vespalib::datastore::EntryRef;

template <bool interleaved_features>
FieldIndex<interleaved_features>::FieldIndex(const index::Schema& schema, uint32_t fieldId)
    : FieldIndex(schema, fieldId, index::FieldLengthInfo())
{
}

template <bool interleaved_features>
FieldIndex<interleaved_features>::FieldIndex(const index::Schema& schema, uint32_t fieldId,
                                             const index::FieldLengthInfo& info)
    : FieldIndexBase(schema, fieldId, info),
      _postingListStore()
{
    using InserterType = OrderedFieldIndexInserter<interleaved_features>;
    _inserter = std::make_unique<InserterType>(*this);
}

template <bool interleaved_features>
FieldIndex<interleaved_features>::~FieldIndex()
{
    _postingListStore.disableFreeLists();
    _postingListStore.disableElemHoldList();
    _dict.disableFreeLists();
    _dict.disableElemHoldList();
    // XXX: Kludge
    for (DictionaryTree::Iterator it = _dict.begin();
         it.valid(); ++it) {
        EntryRef pidx(it.getData());
        if (pidx.valid()) {
            _postingListStore.clear(pidx);
            // Before updating ref
            std::atomic_thread_fence(std::memory_order_release);
            it.writeData(EntryRef().ref());
        }
    }
    _postingListStore.clearBuilder();
    freeze();   // Flush all pending posting list tree freezes
    transferHoldLists();
    _dict.clear();  // Clear dictionary
    freeze();   // Flush pending freeze for dictionary tree.
    transferHoldLists();
    incGeneration();
    trimHoldLists();
}

template <bool interleaved_features>
typename FieldIndex<interleaved_features>::PostingList::Iterator
FieldIndex<interleaved_features>::find(const vespalib::stringref word) const
{
    DictionaryTree::Iterator itr = _dict.find(WordKey(EntryRef()), KeyComp(_wordStore, word));
    if (itr.valid()) {
        return _postingListStore.begin(EntryRef(itr.getData()));
    }
    return typename PostingList::Iterator();
}

template <bool interleaved_features>
typename FieldIndex<interleaved_features>::PostingList::ConstIterator
FieldIndex<interleaved_features>::findFrozen(const vespalib::stringref word) const
{
    auto itr = _dict.getFrozenView().find(WordKey(EntryRef()), KeyComp(_wordStore, word));
    if (itr.valid()) {
        return _postingListStore.beginFrozen(EntryRef(itr.getData()));
    }
    return typename PostingList::Iterator();
}

template <bool interleaved_features>
void
FieldIndex<interleaved_features>::compactFeatures()
{
    std::vector<uint32_t> toHold;

    toHold = _featureStore.startCompact();
    auto itr = _dict.begin();
    uint32_t packedIndex = _fieldId;
    for (; itr.valid(); ++itr) {
        typename PostingListStore::RefType pidx(EntryRef(itr.getData()));
        if (!pidx.valid()) {
            continue;
        }
        uint32_t clusterSize = _postingListStore.getClusterSize(pidx);
        if (clusterSize == 0) {
            const PostingList *tree = _postingListStore.getTreeEntry(pidx);
            auto pitr = tree->begin(_postingListStore.getAllocator());
            for (; pitr.valid(); ++pitr) {
                const PostingListEntryType& posting_entry(pitr.getData());

                // Filter on which buffers to move features from when
                // performing incremental compaction.

                EntryRef newFeatures = _featureStore.moveFeatures(packedIndex, posting_entry.get_features());

                // Features must be written before reference is updated.
                std::atomic_thread_fence(std::memory_order_release);

                // Reference the moved data
                posting_entry.update_features(newFeatures);
            }
        } else {
            const PostingListKeyDataType *shortArray = _postingListStore.getKeyDataEntry(pidx, clusterSize);
            const PostingListKeyDataType *ite = shortArray + clusterSize;
            for (const PostingListKeyDataType *it = shortArray; it < ite; ++it) {
                const PostingListEntryType& posting_entry(it->getData());

                // Filter on which buffers to move features from when
                // performing incremental compaction.

                EntryRef newFeatures = _featureStore.moveFeatures(packedIndex, posting_entry.get_features());

                // Features must be written before reference is updated.
                std::atomic_thread_fence(std::memory_order_release);

                // Reference the moved data
                posting_entry.update_features(newFeatures);
            }
        }
    }
    using generation_t = GenerationHandler::generation_t;
    _featureStore.finishCompact(toHold);
    generation_t generation = _generationHandler.getCurrentGeneration();
    _featureStore.transferHoldLists(generation);
}

template <bool interleaved_features>
void
FieldIndex<interleaved_features>::dump(search::index::IndexBuilder & indexBuilder)
{
    vespalib::stringref word;
    FeatureStore::DecodeContextCooked decoder(nullptr);
    DocIdAndFeatures features;
    vespalib::Array<uint32_t> wordMap(_numUniqueWords + 1, 0);
    _featureStore.setupForField(_fieldId, decoder);
    for (auto itr = _dict.begin(); itr.valid(); ++itr) {
        const WordKey & wk = itr.getKey();
        typename PostingListStore::RefType plist(EntryRef(itr.getData()));
        word = _wordStore.getWord(wk._wordRef);
        if (!plist.valid()) {
            continue;
        }
        indexBuilder.startWord(word);
        uint32_t clusterSize = _postingListStore.getClusterSize(plist);
        if (clusterSize == 0) {
            const PostingList *tree = _postingListStore.getTreeEntry(plist);
            auto pitr = tree->begin(_postingListStore.getAllocator());
            assert(pitr.valid());
            for (; pitr.valid(); ++pitr) {
                features.set_doc_id(pitr.getKey());
                const PostingListEntryType &entry(pitr.getData());
                features.set_num_occs(entry.get_num_occs());
                features.set_field_length(entry.get_field_length());
                _featureStore.setupForReadFeatures(entry.get_features(), decoder);
                decoder.readFeatures(features);
                indexBuilder.add_document(features);
            }
        } else {
            const PostingListKeyDataType *kd =
                _postingListStore.getKeyDataEntry(plist, clusterSize);
            const PostingListKeyDataType *kde = kd + clusterSize;
            for (; kd != kde; ++kd) {
                features.set_doc_id(kd->_key);
                const PostingListEntryType &entry(kd->getData());
                features.set_num_occs(entry.get_num_occs());
                features.set_field_length(entry.get_field_length());
                _featureStore.setupForReadFeatures(entry.get_features(), decoder);
                decoder.readFeatures(features);
                indexBuilder.add_document(features);
            }
        }
        indexBuilder.endWord();
    }
}

template <bool interleaved_features>
vespalib::MemoryUsage
FieldIndex<interleaved_features>::getMemoryUsage() const
{
    vespalib::MemoryUsage usage;
    usage.merge(_wordStore.getMemoryUsage());
    usage.merge(_dict.getMemoryUsage());
    usage.merge(_postingListStore.getMemoryUsage());
    usage.merge(_featureStore.getMemoryUsage());
    usage.merge(_remover.getStore().getMemoryUsage());
    return usage;
}

template <bool interleaved_features>
queryeval::SearchIterator::UP
FieldIndex<interleaved_features>::make_search_iterator(const vespalib::string& term,
                                                       uint32_t field_id,
                                                       const fef::TermFieldMatchDataArray& match_data) const
{
    return search::memoryindex::make_search_iterator<interleaved_features>
            (find(term), getFeatureStore(), field_id, match_data);
}

namespace {

template <bool interleaved_features>
class MemoryTermBlueprint : public SimpleLeafBlueprint {
private:
    using FieldIndexType = FieldIndex<interleaved_features>;
    using PostingListIteratorType = typename FieldIndexType::PostingList::ConstIterator;
    GenerationHandler::Guard _guard;
    PostingListIteratorType _posting_itr;
    const FeatureStore& _feature_store;
    const uint32_t _field_id;
    const bool _use_bit_vector;

public:
    MemoryTermBlueprint(GenerationHandler::Guard&& guard,
                        PostingListIteratorType posting_itr,
                        const FeatureStore& feature_store,
                        const FieldSpecBase& field,
                        uint32_t field_id,
                        bool use_bit_vector)
        : SimpleLeafBlueprint(field),
          _guard(),
          _posting_itr(posting_itr),
          _feature_store(feature_store),
          _field_id(field_id),
          _use_bit_vector(use_bit_vector)
    {
        _guard = std::move(guard);
        HitEstimate estimate(_posting_itr.size(), !_posting_itr.valid());
        setEstimate(estimate);
    }

    SearchIterator::UP createLeafSearch(const TermFieldMatchDataArray& tfmda, bool) const override {
        auto result = make_search_iterator<interleaved_features>(_posting_itr, _feature_store, _field_id, tfmda);
        if (_use_bit_vector) {
            LOG(debug, "Return BooleanMatchIteratorWrapper: field_id(%u), doc_count(%zu)",
                _field_id, _posting_itr.size());
            return std::make_unique<BooleanMatchIteratorWrapper>(std::move(result), tfmda);
        }
        LOG(debug, "Return PostingIterator: field_id(%u), doc_count(%zu)",
            _field_id, _posting_itr.size());
        return result;
    }
};

}

template <bool interleaved_features>
std::unique_ptr<queryeval::SimpleLeafBlueprint>
FieldIndex<interleaved_features>::make_term_blueprint(const vespalib::string& term,
                                                      const queryeval::FieldSpecBase& field,
                                                      uint32_t field_id)
{
    auto guard = takeGenerationGuard();
    auto posting_itr = findFrozen(term);
    bool use_bit_vector = field.isFilter();
    return std::make_unique<MemoryTermBlueprint<interleaved_features>>
            (std::move(guard), posting_itr, getFeatureStore(), field, field_id, use_bit_vector);
}

template class FieldIndex<false>;
template class FieldIndex<true>;

}

using search::memoryindex::FieldIndexBase;

namespace vespalib::btree {

template
class BTreeNodeDataWrap<FieldIndexBase::WordKey, BTreeDefaultTraits::LEAF_SLOTS>;

template
class BTreeNodeT<FieldIndexBase::WordKey, BTreeDefaultTraits::INTERNAL_SLOTS>;

template
class BTreeNodeTT<FieldIndexBase::WordKey,
                  vespalib::datastore::EntryRef,
                  NoAggregated,
                  BTreeDefaultTraits::INTERNAL_SLOTS>;

template
class BTreeNodeTT<FieldIndexBase::WordKey,
                  FieldIndexBase::PostingListPtr,
                  NoAggregated,
                  BTreeDefaultTraits::LEAF_SLOTS>;

template
class BTreeInternalNode<FieldIndexBase::WordKey,
                        NoAggregated,
                        BTreeDefaultTraits::INTERNAL_SLOTS>;

template
class BTreeLeafNode<FieldIndexBase::WordKey,
                    FieldIndexBase::PostingListPtr,
                    NoAggregated,
                    BTreeDefaultTraits::LEAF_SLOTS>;

template
class BTreeNodeStore<FieldIndexBase::WordKey,
                     FieldIndexBase::PostingListPtr,
                     NoAggregated,
                     BTreeDefaultTraits::INTERNAL_SLOTS,
                     BTreeDefaultTraits::LEAF_SLOTS>;

template
class BTreeIterator<FieldIndexBase::WordKey,
                    FieldIndexBase::PostingListPtr,
                    NoAggregated,
                    const FieldIndexBase::KeyComp,
                    BTreeDefaultTraits>;

template
class BTree<FieldIndexBase::WordKey,
            FieldIndexBase::PostingListPtr,
            NoAggregated,
            const FieldIndexBase::KeyComp,
            BTreeDefaultTraits>;

template
class BTreeRoot<FieldIndexBase::WordKey,
                FieldIndexBase::PostingListPtr,
                NoAggregated,
                const FieldIndexBase::KeyComp,
                BTreeDefaultTraits>;

template
class BTreeRootBase<FieldIndexBase::WordKey,
                    FieldIndexBase::PostingListPtr,
                    NoAggregated,
                    BTreeDefaultTraits::INTERNAL_SLOTS,
                    BTreeDefaultTraits::LEAF_SLOTS>;

template
class BTreeNodeAllocator<FieldIndexBase::WordKey,
                         FieldIndexBase::PostingListPtr,
                         NoAggregated,
                         BTreeDefaultTraits::INTERNAL_SLOTS,
                         BTreeDefaultTraits::LEAF_SLOTS>;

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

#include "field_index.h"
#include "ordered_field_index_inserter.h"
#include "posting_iterator.h"
#include <vespa/searchlib/bitcompression/posocccompression.h>
#include <vespa/searchlib/queryeval/booleanmatchiteratorwrapper.h>
#include <vespa/searchlib/queryeval/searchiterator.h>
#include <vespa/searchlib/queryeval/filter_wrapper.h>
#include <vespa/vespalib/btree/btree.hpp>
#include <vespa/vespalib/btree/btreeiterator.hpp>
#include <vespa/vespalib/btree/btreenode.hpp>
#include <vespa/vespalib/btree/btreenodeallocator.hpp>
#include <vespa/vespalib/btree/btreenodestore.hpp>
#include <vespa/vespalib/btree/btreeroot.hpp>
#include <vespa/vespalib/btree/btreestore.hpp>
#include <vespa/vespalib/util/array.hpp>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/stringfmt.h>

#include <vespa/log/log.h>
LOG_SETUP(".searchlib.memoryindex.field_index");

using search::fef::TermFieldMatchDataArray;
using search::index::DocIdAndFeatures;
using search::index::Schema;
using search::index::WordDocElementFeatures;
using search::queryeval::BooleanMatchIteratorWrapper;
using search::queryeval::FieldSpecBase;
using search::queryeval::SearchIterator;
using search::queryeval::SimpleLeafBlueprint;
using vespalib::GenerationHandler;

namespace search::memoryindex {

using vespalib::datastore::EntryRef;

template <bool interleaved_features>
FieldIndex<interleaved_features>::FieldIndex(const index::Schema& schema, uint32_t fieldId)
    : FieldIndex(schema, fieldId, index::FieldLengthInfo())
{
}

template <bool interleaved_features>
FieldIndex<interleaved_features>::FieldIndex(const index::Schema& schema, uint32_t fieldId,
                                             const index::FieldLengthInfo& info)
    : FieldIndexBase(schema, fieldId, info),
      _postingListStore()
{
    using InserterType = OrderedFieldIndexInserter<interleaved_features>;
    _inserter = std::make_unique<InserterType>(*this);
}

template <bool interleaved_features>
FieldIndex<interleaved_features>::~FieldIndex()
{
    _postingListStore.disableFreeLists();
    _postingListStore.disableElemHoldList();
    _dict.disableFreeLists();
    _dict.disableElemHoldList();
    // XXX: Kludge
    for (DictionaryTree::Iterator it = _dict.begin();
         it.valid(); ++it) {
        EntryRef pidx(it.getData());
        if (pidx.valid()) {
            _postingListStore.clear(pidx);
            // Before updating ref
            std::atomic_thread_fence(std::memory_order_release);
            it.writeData(EntryRef().ref());
        }
    }
    _postingListStore.clearBuilder();
    freeze();   // Flush all pending posting list tree freezes
    transferHoldLists();
    _dict.clear();  // Clear dictionary
    freeze();   // Flush pending freeze for dictionary tree.
    transferHoldLists();
    incGeneration();
    trimHoldLists();
}

template <bool interleaved_features>
typename FieldIndex<interleaved_features>::PostingList::Iterator
FieldIndex<interleaved_features>::find(const vespalib::stringref word) const
{
    DictionaryTree::Iterator itr = _dict.find(WordKey(EntryRef()), KeyComp(_wordStore, word));
    if (itr.valid()) {
        return _postingListStore.begin(EntryRef(itr.getData()));
    }
    return typename PostingList::Iterator();
}

template <bool interleaved_features>
typename FieldIndex<interleaved_features>::PostingList::ConstIterator
FieldIndex<interleaved_features>::findFrozen(const vespalib::stringref word) const
{
    auto itr = _dict.getFrozenView().find(WordKey(EntryRef()), KeyComp(_wordStore, word));
    if (itr.valid()) {
        return _postingListStore.beginFrozen(EntryRef(itr.getData()));
    }
    return typename PostingList::Iterator();
}

template <bool interleaved_features>
void
FieldIndex<interleaved_features>::compactFeatures()
{
    std::vector<uint32_t> toHold;

    toHold = _featureStore.startCompact();
    auto itr = _dict.begin();
    uint32_t packedIndex = _fieldId;
    for (; itr.valid(); ++itr) {
        typename PostingListStore::RefType pidx(EntryRef(itr.getData()));
        if (!pidx.valid()) {
            continue;
        }
        uint32_t clusterSize = _postingListStore.getClusterSize(pidx);
        if (clusterSize == 0) {
            const PostingList *tree = _postingListStore.getTreeEntry(pidx);
            auto pitr = tree->begin(_postingListStore.getAllocator());
            for (; pitr.valid(); ++pitr) {
                const PostingListEntryType& posting_entry(pitr.getData());

                // Filter on which buffers to move features from when
                // performing incremental compaction.

                EntryRef newFeatures = _featureStore.moveFeatures(packedIndex, posting_entry.get_features());

                // Features must be written before reference is updated.
                std::atomic_thread_fence(std::memory_order_release);

                // Reference the moved data
                posting_entry.update_features(newFeatures);
            }
        } else {
            const PostingListKeyDataType *shortArray = _postingListStore.getKeyDataEntry(pidx, clusterSize);
            const PostingListKeyDataType *ite = shortArray + clusterSize;
            for (const PostingListKeyDataType *it = shortArray; it < ite; ++it) {
                const PostingListEntryType& posting_entry(it->getData());

                // Filter on which buffers to move features from when
                // performing incremental compaction.

                EntryRef newFeatures = _featureStore.moveFeatures(packedIndex, posting_entry.get_features());

                // Features must be written before reference is updated.
                std::atomic_thread_fence(std::memory_order_release);

                // Reference the moved data
                posting_entry.update_features(newFeatures);
            }
        }
    }
    using generation_t = GenerationHandler::generation_t;
    _featureStore.finishCompact(toHold);
    generation_t generation = _generationHandler.getCurrentGeneration();
    _featureStore.transferHoldLists(generation);
}

template <bool interleaved_features>
void
FieldIndex<interleaved_features>::dump(search::index::IndexBuilder & indexBuilder)
{
    vespalib::stringref word;
    FeatureStore::DecodeContextCooked decoder(nullptr);
    DocIdAndFeatures features;
    vespalib::Array<uint32_t> wordMap(_numUniqueWords + 1, 0);
    _featureStore.setupForField(_fieldId, decoder);
    for (auto itr = _dict.begin(); itr.valid(); ++itr) {
        const WordKey & wk = itr.getKey();
        typename PostingListStore::RefType plist(EntryRef(itr.getData()));
        word = _wordStore.getWord(wk._wordRef);
        if (!plist.valid()) {
            continue;
        }
        indexBuilder.startWord(word);
        uint32_t clusterSize = _postingListStore.getClusterSize(plist);
        if (clusterSize == 0) {
            const PostingList *tree = _postingListStore.getTreeEntry(plist);
            auto pitr = tree->begin(_postingListStore.getAllocator());
            assert(pitr.valid());
            for (; pitr.valid(); ++pitr) {
                features.set_doc_id(pitr.getKey());
                const PostingListEntryType &entry(pitr.getData());
                features.set_num_occs(entry.get_num_occs());
                features.set_field_length(entry.get_field_length());
                _featureStore.setupForReadFeatures(entry.get_features(), decoder);
                decoder.readFeatures(features);
                indexBuilder.add_document(features);
            }
        } else {
            const PostingListKeyDataType *kd =
                _postingListStore.getKeyDataEntry(plist, clusterSize);
            const PostingListKeyDataType *kde = kd + clusterSize;
            for (; kd != kde; ++kd) {
                features.set_doc_id(kd->_key);
                const PostingListEntryType &entry(kd->getData());
                features.set_num_occs(entry.get_num_occs());
                features.set_field_length(entry.get_field_length());
                _featureStore.setupForReadFeatures(entry.get_features(), decoder);
                decoder.readFeatures(features);
                indexBuilder.add_document(features);
            }
        }
        indexBuilder.endWord();
    }
}

template <bool interleaved_features>
vespalib::MemoryUsage
FieldIndex<interleaved_features>::getMemoryUsage() const
{
    vespalib::MemoryUsage usage;
    usage.merge(_wordStore.getMemoryUsage());
    usage.merge(_dict.getMemoryUsage());
    usage.merge(_postingListStore.getMemoryUsage());
    usage.merge(_featureStore.getMemoryUsage());
    usage.merge(_remover.getStore().getMemoryUsage());
    return usage;
}

template <bool interleaved_features>
queryeval::SearchIterator::UP
FieldIndex<interleaved_features>::make_search_iterator(const vespalib::string& term,
                                                       uint32_t field_id,
                                                       const fef::TermFieldMatchDataArray& match_data) const
{
    return search::memoryindex::make_search_iterator<interleaved_features>
            (find(term), getFeatureStore(), field_id, match_data);
}

namespace {

template <bool interleaved_features>
class MemoryTermBlueprint : public SimpleLeafBlueprint {
private:
    using FieldIndexType = FieldIndex<interleaved_features>;
    using PostingListIteratorType = typename FieldIndexType::PostingList::ConstIterator;
    GenerationHandler::Guard _guard;
    PostingListIteratorType _posting_itr;
    const FeatureStore& _feature_store;
    const uint32_t _field_id;
    const bool _use_bit_vector;

public:
    MemoryTermBlueprint(GenerationHandler::Guard&& guard,
                        PostingListIteratorType posting_itr,
                        const FeatureStore& feature_store,
                        const FieldSpecBase& field,
                        uint32_t field_id,
                        bool use_bit_vector)
        : SimpleLeafBlueprint(field),
          _guard(),
          _posting_itr(posting_itr),
          _feature_store(feature_store),
          _field_id(field_id),
          _use_bit_vector(use_bit_vector)
    {
        _guard = std::move(guard);
        HitEstimate estimate(_posting_itr.size(), !_posting_itr.valid());
        setEstimate(estimate);
    }

    SearchIterator::UP createLeafSearch(const TermFieldMatchDataArray& tfmda, bool) const override {
        auto result = make_search_iterator<interleaved_features>(_posting_itr, _feature_store, _field_id, tfmda);
        if (_use_bit_vector) {
            LOG(debug, "Return BooleanMatchIteratorWrapper: field_id(%u), doc_count(%zu)",
                _field_id, _posting_itr.size());
            return std::make_unique<BooleanMatchIteratorWrapper>(std::move(result), tfmda);
        }
        LOG(debug, "Return PostingIterator: field_id(%u), doc_count(%zu)",
            _field_id, _posting_itr.size());
        return result;
    }

    SearchIterator::UP createFilterSearch(bool, FilterConstraint) const override {
        auto wrapper = std::make_unique<queryeval::FilterWrapper>(getState().numFields());
        auto & tfmda = wrapper->tfmda();
        wrapper->wrap(make_search_iterator<interleaved_features>(_posting_itr, _feature_store, _field_id, tfmda));
        return wrapper;
    }
};

}

template <bool interleaved_features>
std::unique_ptr<queryeval::SimpleLeafBlueprint>
FieldIndex<interleaved_features>::make_term_blueprint(const vespalib::string& term,
                                                      const queryeval::FieldSpecBase& field,
                                                      uint32_t field_id)
{
    auto guard = takeGenerationGuard();
    auto posting_itr = findFrozen(term);
    bool use_bit_vector = field.isFilter();
    return std::make_unique<MemoryTermBlueprint<interleaved_features>>
            (std::move(guard), posting_itr, getFeatureStore(), field, field_id, use_bit_vector);
}

template class FieldIndex<false>;
template class FieldIndex<true>;

}

using search::memoryindex::FieldIndexBase;

namespace vespalib::btree {

template
class BTreeNodeDataWrap<FieldIndexBase::WordKey, BTreeDefaultTraits::LEAF_SLOTS>;

template
class BTreeNodeT<FieldIndexBase::WordKey, BTreeDefaultTraits::INTERNAL_SLOTS>;

template
class BTreeNodeTT<FieldIndexBase::WordKey,
                  vespalib::datastore::EntryRef,
                  NoAggregated,
                  BTreeDefaultTraits::INTERNAL_SLOTS>;

template
class BTreeNodeTT<FieldIndexBase::WordKey,
                  FieldIndexBase::PostingListPtr,
                  NoAggregated,
                  BTreeDefaultTraits::LEAF_SLOTS>;

template
class BTreeInternalNode<FieldIndexBase::WordKey,
                        NoAggregated,
                        BTreeDefaultTraits::INTERNAL_SLOTS>;

template
class BTreeLeafNode<FieldIndexBase::WordKey,
                    FieldIndexBase::PostingListPtr,
                    NoAggregated,
                    BTreeDefaultTraits::LEAF_SLOTS>;

template
class BTreeNodeStore<FieldIndexBase::WordKey,
                     FieldIndexBase::PostingListPtr,
                     NoAggregated,
                     BTreeDefaultTraits::INTERNAL_SLOTS,
                     BTreeDefaultTraits::LEAF_SLOTS>;

template
class BTreeIterator<FieldIndexBase::WordKey,
                    FieldIndexBase::PostingListPtr,
                    NoAggregated,
                    const FieldIndexBase::KeyComp,
                    BTreeDefaultTraits>;

template
class BTree<FieldIndexBase::WordKey,
            FieldIndexBase::PostingListPtr,
            NoAggregated,
            const FieldIndexBase::KeyComp,
            BTreeDefaultTraits>;

template
class BTreeRoot<FieldIndexBase::WordKey,
                FieldIndexBase::PostingListPtr,
                NoAggregated,
                const FieldIndexBase::KeyComp,
                BTreeDefaultTraits>;

template
class BTreeRootBase<FieldIndexBase::WordKey,
                    FieldIndexBase::PostingListPtr,
                    NoAggregated,
                    BTreeDefaultTraits::INTERNAL_SLOTS,
                    BTreeDefaultTraits::LEAF_SLOTS>;

template
class BTreeNodeAllocator<FieldIndexBase::WordKey,
                         FieldIndexBase::PostingListPtr,
                         NoAggregated,
                         BTreeDefaultTraits::INTERNAL_SLOTS,
                         BTreeDefaultTraits::LEAF_SLOTS>;

}
<|endoftext|>


<commit_before>#include <Eigen/Core>
#include <iostream>
#include <iomanip>
#include <string>

using Eigen::MatrixXd;
using Eigen::VectorXd;

void eigs_sym_F77(MatrixXd &M, VectorXd &init_resid, int k, int m, double &time_used, double &prec_err);
void eigs_gen_F77(MatrixXd &M, VectorXd &init_resid, int k, int m, double &time_used, double &prec_err);
void eigs_sym_Cpp(MatrixXd &M, VectorXd &init_resid, int k, int m, double &time_used, double &prec_err);
void eigs_gen_Cpp(MatrixXd &M, VectorXd &init_resid, int k, int m, double &time_used, double &prec_err);

void print_header(std::string title)
{
    const int width = 80;
    const char sep = ' ';

    std::cout << std::endl << std::string(width, '=') << std::endl;
    std::cout << std::string((width - title.length()) / 2, ' ') << title << std::endl;
    std::cout << std::string(width, '-') << std::endl;

    std::cout << std::left << std::setw(12) << std::setfill(sep) << "mat_size";
    std::cout << std::left << std::setw(11) << std::setfill(sep) << "dataset";
    std::cout << std::left << std::setw(15) << std::setfill(sep) << "F77_time/ms";
    std::cout << std::left << std::setw(13) << std::setfill(sep) << "F77_error";
    std::cout << std::left << std::setw(15) << std::setfill(sep) << "C++_time/ms";
    std::cout << std::left << std::setw(13) << std::setfill(sep) << "C++_error";
    std::cout << std::endl;

    std::cout << std::string(width, '-') << std::endl;
}

void print_row(int n, int dataset, double time_f77, double err_f77, double time_cpp, double err_cpp)
{
    const char sep = ' ';

    std::cout << std::left << std::setw(12) << std::setfill(sep) << n;
    std::cout << std::left << std::setw(11) << std::setfill(sep) << dataset;
    std::cout << std::left << std::setw(15) << std::setfill(sep) << time_f77;
    std::cout << std::left << std::setw(13) << std::setfill(sep) << err_f77;
    std::cout << std::left << std::setw(15) << std::setfill(sep) << time_cpp;
    std::cout << std::left << std::setw(13) << std::setfill(sep) << err_cpp;
    std::cout << std::endl;
}

void print_footer()
{
    const int width = 80;
    std::cout << std::string(width, '=') << std::endl << std::endl;
}

void run_eigs_sym(int n_experiment, int n_replicate, int n, int k, int m)
{
    double time_f77, time_cpp;
    double err_f77, err_cpp;

    for(int i = 0; i < n_experiment; i++)
    {
        MatrixXd A = MatrixXd::Random(n, n);
        MatrixXd M = A.transpose() + A;

        VectorXd init_resid = VectorXd::Random(M.cols());
        init_resid.array() -= 0.5;
        init_resid = M * init_resid;

        for(int j = 0; j < n_replicate; j++)
        {
            eigs_sym_F77(M, init_resid, k, m, time_f77, err_f77);
            eigs_sym_Cpp(M, init_resid, k, m, time_cpp, err_cpp);
            print_row(n, i + 1, time_f77, err_f77, time_cpp, err_cpp);
        }
    }
}

void run_eigs_gen(int n_experiment, int n_replicate, int n, int k, int m)
{
    double time_f77, time_cpp;
    double err_f77, err_cpp;

    for(int i = 0; i < n_experiment; i++)
    {
        MatrixXd A = MatrixXd::Random(n, n);

        VectorXd init_resid = VectorXd::Random(A.cols());
        init_resid.array() -= 0.5;
        init_resid = A * init_resid;

        for(int j = 0; j < n_replicate; j++)
        {
            eigs_gen_F77(A, init_resid, k, m, time_f77, err_f77);
            eigs_gen_Cpp(A, init_resid, k, m, time_cpp, err_cpp);
            print_row(n, i + 1, time_f77, err_f77, time_cpp, err_cpp);
        }
    }
}

int main()
{
    srand(123);
    int n_experiment = 5;
    int n_replicate = 5;

    print_header("eigs_sym");
    run_eigs_sym(n_experiment, n_replicate, 100, 10, 20);
    run_eigs_sym(n_experiment, n_replicate, 1000, 10, 30);
    print_footer();

    print_header("eigs_gen");
    run_eigs_gen(n_experiment, n_replicate, 100, 10, 20);
    run_eigs_gen(n_experiment, n_replicate, 1000, 10, 30);
    print_footer();

    return 0;
}
<commit_msg>more replicates<commit_after>#include <Eigen/Core>
#include <iostream>
#include <iomanip>
#include <string>

using Eigen::MatrixXd;
using Eigen::VectorXd;

void eigs_sym_F77(MatrixXd &M, VectorXd &init_resid, int k, int m, double &time_used, double &prec_err);
void eigs_gen_F77(MatrixXd &M, VectorXd &init_resid, int k, int m, double &time_used, double &prec_err);
void eigs_sym_Cpp(MatrixXd &M, VectorXd &init_resid, int k, int m, double &time_used, double &prec_err);
void eigs_gen_Cpp(MatrixXd &M, VectorXd &init_resid, int k, int m, double &time_used, double &prec_err);

void print_header(std::string title)
{
    const int width = 80;
    const char sep = ' ';

    std::cout << std::endl << std::string(width, '=') << std::endl;
    std::cout << std::string((width - title.length()) / 2, ' ') << title << std::endl;
    std::cout << std::string(width, '-') << std::endl;

    std::cout << std::left << std::setw(12) << std::setfill(sep) << "mat_size";
    std::cout << std::left << std::setw(11) << std::setfill(sep) << "dataset";
    std::cout << std::left << std::setw(15) << std::setfill(sep) << "F77_time/ms";
    std::cout << std::left << std::setw(13) << std::setfill(sep) << "F77_error";
    std::cout << std::left << std::setw(15) << std::setfill(sep) << "C++_time/ms";
    std::cout << std::left << std::setw(13) << std::setfill(sep) << "C++_error";
    std::cout << std::endl;

    std::cout << std::string(width, '-') << std::endl;
}

void print_row(int n, int dataset, double time_f77, double err_f77, double time_cpp, double err_cpp)
{
    const char sep = ' ';

    std::cout << std::left << std::setw(12) << std::setfill(sep) << n;
    std::cout << std::left << std::setw(11) << std::setfill(sep) << dataset;
    std::cout << std::left << std::setw(15) << std::setfill(sep) << time_f77;
    std::cout << std::left << std::setw(13) << std::setfill(sep) << err_f77;
    std::cout << std::left << std::setw(15) << std::setfill(sep) << time_cpp;
    std::cout << std::left << std::setw(13) << std::setfill(sep) << err_cpp;
    std::cout << std::endl;
}

void print_footer()
{
    const int width = 80;
    std::cout << std::string(width, '=') << std::endl << std::endl;
}

void run_eigs_sym(int n_experiment, int n_replicate, int n, int k, int m)
{
    double time_f77, time_cpp;
    double err_f77, err_cpp;

    for(int i = 0; i < n_experiment; i++)
    {
        MatrixXd A = MatrixXd::Random(n, n);
        MatrixXd M = A.transpose() + A;

        VectorXd init_resid = VectorXd::Random(M.cols());
        init_resid.array() -= 0.5;
        init_resid = M * init_resid;

        for(int j = 0; j < n_replicate; j++)
        {
            eigs_sym_F77(M, init_resid, k, m, time_f77, err_f77);
            eigs_sym_Cpp(M, init_resid, k, m, time_cpp, err_cpp);
            print_row(n, i + 1, time_f77, err_f77, time_cpp, err_cpp);
        }
    }
}

void run_eigs_gen(int n_experiment, int n_replicate, int n, int k, int m)
{
    double time_f77, time_cpp;
    double err_f77, err_cpp;

    for(int i = 0; i < n_experiment; i++)
    {
        MatrixXd A = MatrixXd::Random(n, n);

        VectorXd init_resid = VectorXd::Random(A.cols());
        init_resid.array() -= 0.5;
        init_resid = A * init_resid;

        for(int j = 0; j < n_replicate; j++)
        {
            eigs_gen_F77(A, init_resid, k, m, time_f77, err_f77);
            eigs_gen_Cpp(A, init_resid, k, m, time_cpp, err_cpp);
            print_row(n, i + 1, time_f77, err_f77, time_cpp, err_cpp);
        }
    }
}

int main()
{
    srand(123);
    int n_experiment = 5;
    int n_replicate = 10;

    print_header("eigs_sym");
    run_eigs_sym(n_experiment, n_replicate, 100, 10, 20);
    run_eigs_sym(n_experiment, n_replicate, 1000, 10, 30);
    print_footer();

    print_header("eigs_gen");
    run_eigs_gen(n_experiment, n_replicate, 100, 10, 20);
    run_eigs_gen(n_experiment, n_replicate, 1000, 10, 30);
    print_footer();

    return 0;
}
<|endoftext|>


<commit_before>//--------------------------------------------------------------------------//
/// Copyright (c) 2017 by Milos Tosic. All Rights Reserved.                ///
/// License: http://www.opensource.org/licenses/BSD-2-Clause               ///
//--------------------------------------------------------------------------//

#include <rbase_pch.h>

static int s_rbaseWarningKill;<commit_msg>Remove warning kill var<commit_after>//--------------------------------------------------------------------------//
/// Copyright (c) 2017 by Milos Tosic. All Rights Reserved.                ///
/// License: http://www.opensource.org/licenses/BSD-2-Clause               ///
//--------------------------------------------------------------------------//

#include <rbase_pch.h>

<|endoftext|>


<commit_before>#pragma once

// ----------------------------------------------------------------------
// std::vector<std::string> split(const std::string& s, const std::string& delim, bool keep_empty = Split::KeepEmpty)
// Split string by delimiter into array of substrings
// std::vector<std::string> split(const std::string& s, const std::string& delim, bool keep_empty = Split::KeepEmpty)

// std::string strip(std::string source)
// Removes leading and trailing spaces from string
//
// ----------------------------------------------------------------------

#include <string>
#include <vector>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <utility>
#include <initializer_list>
#include <numeric>
#include <sstream>
#include <iomanip>

#include "acmacs-base/to-string.hh"

// ----------------------------------------------------------------------

namespace string
{
    enum class Split { RemoveEmpty, KeepEmpty };

      // http://stackoverflow.com/questions/236129/split-a-string-in-c
    inline std::vector<std::string> split(std::string s, std::string delim, Split keep_empty = Split::KeepEmpty)
    {
        std::vector<std::string> result;
        if (! delim.empty()) {
            for (std::string::iterator substart = s.begin(), subend = substart; substart <= s.end(); substart = subend + static_cast<std::string::difference_type>(delim.size())) {
                subend = std::search(substart, s.end(), delim.begin(), delim.end());
                if (substart != subend || keep_empty == Split::KeepEmpty) {
                    result.push_back(std::string(substart, subend));
                }
            }
        }
        else {
            result.push_back(s);
        }
        return result;
    }

      // ----------------------------------------------------------------------

    inline std::string first_letter_of_words(std::string s)
    {
        std::string result;
        bool add = true;
        for (char c: s) {
            if (c == ' ') {
                add = true;
            }
            else if (add) {
                result.push_back(c);
                add = false;
            }
        }
        return result;
    }

      // ----------------------------------------------------------------------

    namespace _internal {
        template <typename InputIterator, typename Source> inline std::pair<InputIterator, InputIterator> strip_begin_end(Source& source)
        {
            auto predicate = [](auto c) { return std::isspace(c); }; // have to use lambda, other compiler cannot infer Predicate type from isspace
            auto e = std::find_if_not(source.rbegin(), source.rend(), predicate);
            auto b = std::find_if_not(source.begin(), e.base(), predicate);
            return std::make_pair(b, e.base());
        }
    } // namespace _internal

    // inline std::string& strip(std::string& source)
    // {
    //     auto be = _internal::strip_begin_end<std::string::iterator>(source);
    //     source.erase(be.second, source.end()); // erase at the end first
    //     source.erase(source.begin(), be.first); // invalidates be.second!
    //     return source;
    // }

    // inline std::string strip(std::string&& source)
    // {
    //     auto be = _internal::strip_begin_end<std::string::iterator>(source);
    //     source.erase(be.second, source.end()); // erase at the end first
    //     source.erase(source.begin(), be.first); // invalidates be.second!
    //     return source;
    // }

    inline std::string strip(std::string source)
    {
        auto be = _internal::strip_begin_end<std::string::const_iterator>(source);
        return std::string(be.first, be.second);
    }

      // ----------------------------------------------------------------------

    inline std::string replace(std::string source, std::string look_for, std::string replace_with)
    {
        std::string result;
        std::string::size_type start = 0;
        while (true) {
            const auto pos = source.find(look_for, start);
            if (pos != std::string::npos) {
                result.append(source.begin() + static_cast<std::string::difference_type>(start), source.begin() + static_cast<std::string::difference_type>(pos));
                result.append(replace_with);
                start = pos + look_for.size();
            }
            else {
                result.append(source.begin() + static_cast<std::string::difference_type>(start), source.end());
                break;
            }
        }
        return result;
    }

      // ----------------------------------------------------------------------

    // inline std::string& lower(std::string& source)
    // {
    //     std::transform(source.begin(), source.end(), source.begin(), ::tolower);
    //     return source;
    // }

    inline std::string lower(std::string source)
    {
        std::string result;
        std::transform(source.begin(), source.end(), std::back_inserter(result), ::tolower);
        return result;
    }

    // inline std::string& upper(std::string& source)
    // {
    //     std::transform(source.begin(), source.end(), source.begin(), ::toupper);
    //     return source;
    // }

    inline std::string upper(std::string source)
    {
        std::string result;
        std::transform(source.begin(), source.end(), std::back_inserter(result), ::toupper);
        return result;
    }

    // inline std::string& capitalize(std::string& source)
    // {
    //     if (!source.empty()) {
    //         std::transform(source.begin(), source.begin() + 1, source.begin(), ::toupper);
    //         std::transform(source.begin() + 1, source.end(), source.begin() + 1, ::tolower);
    //     }
    //     return source;
    // }

    inline std::string capitalize(std::string source)
    {
        std::string result;
        if (!source.empty()) {
            std::transform(source.begin(), source.begin() + 1, std::back_inserter(result), ::toupper);
            std::transform(source.begin() + 1, source.end(), std::back_inserter(result), ::tolower);
        }
        return result;
    }

    template <typename Iterator> inline std::string join(std::string separator, Iterator first, Iterator last)
    {
        std::string result;
        if (first != last) {
              // Note last - first below does not supported for std::set
              // const size_t resulting_size = std::accumulate(first, last, separator.size() * static_cast<size_t>(last - first - 1), [](size_t acc, const std::string& n) -> size_t { return acc + n.size(); });
              // result.reserve(resulting_size);
            for ( ; first != last; ++first) {
                const auto f_s = acmacs::to_string(*first);
                if (!f_s.empty()) {
                    if (!result.empty())
                        result.append(separator);
                    result.append(f_s);
                }
            }
        }
        return result;
    }

    template <typename Collection> inline std::string join(std::string separator, const Collection& values)
    {
        return join(separator, std::begin(values), std::end(values));
    }

    inline std::string join(std::string separator, std::initializer_list<std::string>&& values)
    {
        return join(separator, std::begin(values), std::end(values));
    }

    inline std::string join(std::initializer_list<std::string>&& parts)
    {
        std::vector<std::string> p{parts};
        return join(" ", std::begin(p), std::remove(std::begin(p), std::end(p), std::string()));
    }

    enum ShowBase { NotShowBase, ShowBase };
    enum OutputCase { Uppercase, Lowercase };

    template <typename T, typename = std::enable_if<std::is_integral<T>::value>> inline std::string to_hex_string(T aValue, enum ShowBase aShowBase, OutputCase aOutputCase = Uppercase)
    {
        std::ostringstream stream;
          // stream << (aShowBase == ShowBase ? std::showbase : std::noshowbase);
        if (aShowBase == ShowBase)
            stream << "0x";
        stream << std::setfill('0') << std::setw(sizeof(aValue)*2) << std::hex << std::noshowbase;
        stream << (aOutputCase == Uppercase ? std::uppercase : std::nouppercase);
        if constexpr (std::is_same_v<T, char> || std::is_same_v<T, unsigned char>) {
                stream << static_cast<unsigned>(aValue);
            }
        else {
            stream << aValue;
        }
        return stream.str();
    }

    template <typename T> inline std::string to_hex_string(const T* aPtr)
    {
        std::ostringstream stream;
        const void* value = reinterpret_cast<const void*>(aPtr);
        stream << value; // std::setfill('0') << std::setw(sizeof(value)*2) << std::hex << value;
        return stream.str();
    }

// ----------------------------------------------------------------------

} // namespace string

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>acmacs::string::join<commit_after>#pragma once

// ----------------------------------------------------------------------
// std::vector<std::string> split(const std::string& s, const std::string& delim, bool keep_empty = Split::KeepEmpty)
// Split string by delimiter into array of substrings
// std::vector<std::string> split(const std::string& s, const std::string& delim, bool keep_empty = Split::KeepEmpty)

// std::string strip(std::string source)
// Removes leading and trailing spaces from string
//
// ----------------------------------------------------------------------

#include <string>
#include <vector>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <utility>
#include <initializer_list>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <functional>

#include "acmacs-base/to-string.hh"

// ----------------------------------------------------------------------

namespace string
{
    enum class Split { RemoveEmpty, KeepEmpty };

      // http://stackoverflow.com/questions/236129/split-a-string-in-c
    inline std::vector<std::string> split(std::string s, std::string delim, Split keep_empty = Split::KeepEmpty)
    {
        std::vector<std::string> result;
        if (! delim.empty()) {
            for (std::string::iterator substart = s.begin(), subend = substart; substart <= s.end(); substart = subend + static_cast<std::string::difference_type>(delim.size())) {
                subend = std::search(substart, s.end(), delim.begin(), delim.end());
                if (substart != subend || keep_empty == Split::KeepEmpty) {
                    result.push_back(std::string(substart, subend));
                }
            }
        }
        else {
            result.push_back(s);
        }
        return result;
    }

      // ----------------------------------------------------------------------

    inline std::string first_letter_of_words(std::string s)
    {
        std::string result;
        bool add = true;
        for (char c: s) {
            if (c == ' ') {
                add = true;
            }
            else if (add) {
                result.push_back(c);
                add = false;
            }
        }
        return result;
    }

      // ----------------------------------------------------------------------

    namespace _internal {
        template <typename InputIterator, typename Source> inline std::pair<InputIterator, InputIterator> strip_begin_end(Source& source)
        {
            auto predicate = [](auto c) { return std::isspace(c); }; // have to use lambda, other compiler cannot infer Predicate type from isspace
            auto e = std::find_if_not(source.rbegin(), source.rend(), predicate);
            auto b = std::find_if_not(source.begin(), e.base(), predicate);
            return std::make_pair(b, e.base());
        }
    } // namespace _internal

    // inline std::string& strip(std::string& source)
    // {
    //     auto be = _internal::strip_begin_end<std::string::iterator>(source);
    //     source.erase(be.second, source.end()); // erase at the end first
    //     source.erase(source.begin(), be.first); // invalidates be.second!
    //     return source;
    // }

    // inline std::string strip(std::string&& source)
    // {
    //     auto be = _internal::strip_begin_end<std::string::iterator>(source);
    //     source.erase(be.second, source.end()); // erase at the end first
    //     source.erase(source.begin(), be.first); // invalidates be.second!
    //     return source;
    // }

    inline std::string strip(std::string source)
    {
        auto be = _internal::strip_begin_end<std::string::const_iterator>(source);
        return std::string(be.first, be.second);
    }

      // ----------------------------------------------------------------------

    inline std::string replace(std::string source, std::string look_for, std::string replace_with)
    {
        std::string result;
        std::string::size_type start = 0;
        while (true) {
            const auto pos = source.find(look_for, start);
            if (pos != std::string::npos) {
                result.append(source.begin() + static_cast<std::string::difference_type>(start), source.begin() + static_cast<std::string::difference_type>(pos));
                result.append(replace_with);
                start = pos + look_for.size();
            }
            else {
                result.append(source.begin() + static_cast<std::string::difference_type>(start), source.end());
                break;
            }
        }
        return result;
    }

      // ----------------------------------------------------------------------

    // inline std::string& lower(std::string& source)
    // {
    //     std::transform(source.begin(), source.end(), source.begin(), ::tolower);
    //     return source;
    // }

    inline std::string lower(std::string source)
    {
        std::string result;
        std::transform(source.begin(), source.end(), std::back_inserter(result), ::tolower);
        return result;
    }

    // inline std::string& upper(std::string& source)
    // {
    //     std::transform(source.begin(), source.end(), source.begin(), ::toupper);
    //     return source;
    // }

    inline std::string upper(std::string source)
    {
        std::string result;
        std::transform(source.begin(), source.end(), std::back_inserter(result), ::toupper);
        return result;
    }

    // inline std::string& capitalize(std::string& source)
    // {
    //     if (!source.empty()) {
    //         std::transform(source.begin(), source.begin() + 1, source.begin(), ::toupper);
    //         std::transform(source.begin() + 1, source.end(), source.begin() + 1, ::tolower);
    //     }
    //     return source;
    // }

    inline std::string capitalize(std::string source)
    {
        std::string result;
        if (!source.empty()) {
            std::transform(source.begin(), source.begin() + 1, std::back_inserter(result), ::toupper);
            std::transform(source.begin() + 1, source.end(), std::back_inserter(result), ::tolower);
        }
        return result;
    }

    template <typename Iterator> inline std::string join(std::string separator, Iterator first, Iterator last)
    {
        std::string result;
        if (first != last) {
              // Note last - first below does not supported for std::set
              // const size_t resulting_size = std::accumulate(first, last, separator.size() * static_cast<size_t>(last - first - 1), [](size_t acc, const std::string& n) -> size_t { return acc + n.size(); });
              // result.reserve(resulting_size);
            for ( ; first != last; ++first) {
                const auto f_s = acmacs::to_string(*first);
                if (!f_s.empty()) {
                    if (!result.empty())
                        result.append(separator);
                    result.append(f_s);
                }
            }
        }
        return result;
    }

    template <typename Iterator, typename Converter> inline std::string join(std::string separator, Iterator first, Iterator last, Converter convert)
    {
        std::string result;
        for ( ; first != last; ++first) {
            const auto f_s = convert(*first);
            if (!f_s.empty()) {
                if (!result.empty())
                    result.append(separator);
                result.append(f_s);
            }
        }
        return result;
    }

    template <typename Collection> inline std::string join(std::string separator, const Collection& values)
    {
        return join(separator, std::begin(values), std::end(values));
    }

    inline std::string join(std::string separator, std::initializer_list<std::string>&& values)
    {
        return join(separator, std::begin(values), std::end(values));
    }

    inline std::string join(std::initializer_list<std::string>&& parts)
    {
        std::vector<std::string> p{parts};
        return join(" ", std::begin(p), std::remove(std::begin(p), std::end(p), std::string()));
    }

    enum ShowBase { NotShowBase, ShowBase };
    enum OutputCase { Uppercase, Lowercase };

    template <typename T, typename = std::enable_if<std::is_integral<T>::value>> inline std::string to_hex_string(T aValue, enum ShowBase aShowBase, OutputCase aOutputCase = Uppercase)
    {
        std::ostringstream stream;
          // stream << (aShowBase == ShowBase ? std::showbase : std::noshowbase);
        if (aShowBase == ShowBase)
            stream << "0x";
        stream << std::setfill('0') << std::setw(sizeof(aValue)*2) << std::hex << std::noshowbase;
        stream << (aOutputCase == Uppercase ? std::uppercase : std::nouppercase);
        if constexpr (std::is_same_v<T, char> || std::is_same_v<T, unsigned char>) {
                stream << static_cast<unsigned>(aValue);
            }
        else {
            stream << aValue;
        }
        return stream.str();
    }

    template <typename T> inline std::string to_hex_string(const T* aPtr)
    {
        std::ostringstream stream;
        const void* value = reinterpret_cast<const void*>(aPtr);
        stream << value; // std::setfill('0') << std::setw(sizeof(value)*2) << std::hex << value;
        return stream.str();
    }

// ----------------------------------------------------------------------

} // namespace string

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please
** contact Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "filterdialog.h"

#include "qtcontacts.h"
#include <QtGui>

FilterDialog::FilterDialog()
{
    state = -1; // not yet opened.
    noFiltersYet = true;
    expressionSoFar = "";

    title = new QLabel(tr("Contact Search"));
    value = new QLineEdit;
    field = new QComboBox;
    match = new QComboBox;
    join = new QComboBox;
    expression = new QLabel;

    cancel = new QPushButton(tr("Cancel"));
    add = new QPushButton(tr("Add Filter"));
    done = new QPushButton(tr("Done"));

    connect(cancel, SIGNAL(clicked()), this, SLOT(cancelClicked()));
    connect(add, SIGNAL(clicked()), this, SLOT(addClicked()));
    connect(done, SIGNAL(clicked()), this, SLOT(doneClicked()));

    field->addItem(tr("Name"));
    field->addItem(tr("Phone Number"));
    field->addItem(tr("Email Address"));

    match->addItem(tr("Exact Match"));
    match->addItem(tr("Starts With"));
    match->addItem(tr("Contains"));
    match->addItem(tr("Ends With"));

    join->addItem(tr("AND"));
    join->addItem(tr("OR"));

    formLayout = new QFormLayout;
    formLayout->addRow("Search String:", value);
    formLayout->addRow("In Field:", field);
    formLayout->addRow("With Criteria:", match);
    formLayout->addRow("Join Method:", join);
    formLayout->addRow("Cumulative Expression:", expression);

    btnLayout = new QHBoxLayout;
    btnLayout->addWidget(cancel);
    btnLayout->addWidget(add);
    btnLayout->addWidget(done);

    vertLayout = new QVBoxLayout;
    vertLayout->addWidget(title);
    vertLayout->addLayout(formLayout);
    vertLayout->addLayout(btnLayout);

    setLayout(vertLayout);
}

FilterDialog::~FilterDialog()
{
}

QContactFilter FilterDialog::filter() const
{
    QContactIntersectionFilter retn = total;
    total = QContactIntersectionFilter(); // clear the filter.
    expressionSoFar = "";
    noFiltersYet = true;
    return retn;
}

int FilterDialog::status() const
{
    // -1 = cancelled
    //  0 = in progress
    //  1 = accepted
    return state;
}

void FilterDialog::cancelClicked()
{
    total = QContactIntersectionFilter();
    noFiltersYet = true;
    expressionSoFar = "";
    state = -1;
    hide();
    emit hidden();
}

void FilterDialog::addClicked()
{
    state = 0;

    QString exprName;
    QString exprMatch;
    QString exprJoin;

    QContactDetailFilter fil;
    QString defName;
    QString fieldName;
    switch (field->currentIndex()) {
        case 0:
        {
            // name
            defName = QString(QLatin1String(QContactDisplayLabel::DefinitionName));
            fieldName = QString(QLatin1String(QContactDisplayLabel::FieldLabel));

            exprName = "NAME";
        }
        break;

        case 1:
        {
            // phone number
            defName = QString(QLatin1String(QContactPhoneNumber::DefinitionName));
            fieldName = QString(QLatin1String(QContactPhoneNumber::FieldNumber));

            exprName = "PHONENUMBER";
        }
        break;

        default:
        {
            // email address
            defName = QString(QLatin1String(QContactEmailAddress::DefinitionName));
            fieldName = QString(QLatin1String(QContactEmailAddress::FieldEmailAddress));

            exprName = "EMAILADDRESS";
        }
        break;

    }
    fil.setDetailDefinitionName(defName, fieldName);
    fil.setValue(value->text());

    Qt::MatchFlags matchFlags;
    switch (match->currentIndex()) {
        case 0:
        {
            matchFlags |= Qt::MatchExactly;

            exprMatch = "EQUALS";
        }
        break;

        case 1:
        {
            matchFlags |= Qt::MatchStartsWith;

            exprMatch = "STARTSWITH";
        }
        break;

        case 2:
        {
            matchFlags |= Qt::MatchContains;

            exprMatch = "CONTAINS";
        }
        break;

        default:
        {
            matchFlags |= Qt::MatchEndsWith;

            exprMatch = "ENDSWITH";
        }
        break;
    }
    fil.setMatchFlags(matchFlags);

    // if OR then join with OR
    noFiltersYet = false; // either way, have added a filter.
    if (join->currentIndex() == 1) {
        QContactUnionFilter ufil;
        ufil << total << fil;
        QContactIntersectionFilter ifil;
        ifil << ufil;
        total = ifil;

        exprJoin = "OR";
    } else {
        // otherwise, just AND.
        total << fil;

        exprJoin = "AND";
    }

    // set the expression so far
    if (!expressionSoFar.isEmpty())
        expressionSoFar += " " + exprJoin + " ";
    expressionSoFar += exprName + " " + exprMatch + " " + value->text();
    expression->setText(expressionSoFar);

    // now reset the UI elements.
    value->setText("");
    field->setCurrentIndex(0);
    match->setCurrentIndex(0);
    join->setCurrentIndex(0);
}

void FilterDialog::doneClicked()
{
    state = 1;
    hide();
    emit hidden();
}

void FilterDialog::showDialog()
{
    state = 0;
    expressionSoFar = "";
    show();
}
<commit_msg>Fix bug in filter dialog code in async example<commit_after>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please
** contact Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "filterdialog.h"

#include "qtcontacts.h"
#include <QtGui>

FilterDialog::FilterDialog()
{
    state = -1; // not yet opened.
    noFiltersYet = true;
    expressionSoFar = "";

    title = new QLabel(tr("Contact Search"));
    value = new QLineEdit;
    field = new QComboBox;
    match = new QComboBox;
    join = new QComboBox;
    expression = new QLabel;

    cancel = new QPushButton(tr("Cancel"));
    add = new QPushButton(tr("Add Filter"));
    done = new QPushButton(tr("Done"));

    connect(cancel, SIGNAL(clicked()), this, SLOT(cancelClicked()));
    connect(add, SIGNAL(clicked()), this, SLOT(addClicked()));
    connect(done, SIGNAL(clicked()), this, SLOT(doneClicked()));

    field->addItem(tr("Name"));
    field->addItem(tr("Phone Number"));
    field->addItem(tr("Email Address"));

    match->addItem(tr("Exact Match"));
    match->addItem(tr("Starts With"));
    match->addItem(tr("Contains"));
    match->addItem(tr("Ends With"));

    join->addItem(tr("AND"));
    join->addItem(tr("OR"));

    formLayout = new QFormLayout;
    formLayout->addRow("Search String:", value);
    formLayout->addRow("In Field:", field);
    formLayout->addRow("With Criteria:", match);
    formLayout->addRow("Join Method:", join);
    formLayout->addRow("Cumulative Expression:", expression);

    btnLayout = new QHBoxLayout;
    btnLayout->addWidget(cancel);
    btnLayout->addWidget(add);
    btnLayout->addWidget(done);

    vertLayout = new QVBoxLayout;
    vertLayout->addWidget(title);
    vertLayout->addLayout(formLayout);
    vertLayout->addLayout(btnLayout);

    setLayout(vertLayout);
}

FilterDialog::~FilterDialog()
{
}

QContactFilter FilterDialog::filter() const
{
    return total;
}

int FilterDialog::status() const
{
    // -1 = cancelled
    //  0 = in progress
    //  1 = accepted
    return state;
}

void FilterDialog::cancelClicked()
{
    total = QContactIntersectionFilter();
    noFiltersYet = true;
    state = -1;
    hide();
    emit hidden();
}

void FilterDialog::addClicked()
{
    state = 0;

    QString exprName;
    QString exprMatch;
    QString exprJoin;

    QContactDetailFilter fil;
    QString defName;
    QString fieldName;
    switch (field->currentIndex()) {
        case 0:
        {
            // name
            defName = QString(QLatin1String(QContactDisplayLabel::DefinitionName));
            fieldName = QString(QLatin1String(QContactDisplayLabel::FieldLabel));

            exprName = "NAME";
        }
        break;

        case 1:
        {
            // phone number
            defName = QString(QLatin1String(QContactPhoneNumber::DefinitionName));
            fieldName = QString(QLatin1String(QContactPhoneNumber::FieldNumber));

            exprName = "PHONENUMBER";
        }
        break;

        default:
        {
            // email address
            defName = QString(QLatin1String(QContactEmailAddress::DefinitionName));
            fieldName = QString(QLatin1String(QContactEmailAddress::FieldEmailAddress));

            exprName = "EMAILADDRESS";
        }
        break;

    }
    fil.setDetailDefinitionName(defName, fieldName);
    fil.setValue(value->text());

    Qt::MatchFlags matchFlags;
    switch (match->currentIndex()) {
        case 0:
        {
            matchFlags |= Qt::MatchExactly;

            exprMatch = "EQUALS";
        }
        break;

        case 1:
        {
            matchFlags |= Qt::MatchStartsWith;

            exprMatch = "STARTSWITH";
        }
        break;

        case 2:
        {
            matchFlags |= Qt::MatchContains;

            exprMatch = "CONTAINS";
        }
        break;

        default:
        {
            matchFlags |= Qt::MatchEndsWith;

            exprMatch = "ENDSWITH";
        }
        break;
    }
    fil.setMatchFlags(matchFlags);

    // if OR then join with OR
    noFiltersYet = false; // either way, have added a filter.
    if (join->currentIndex() == 1) {
        QContactUnionFilter ufil;
        ufil << total << fil;
        QContactIntersectionFilter ifil;
        ifil << ufil;
        total = ifil;

        exprJoin = "OR";
    } else {
        // otherwise, just AND.
        total << fil;

        exprJoin = "AND";
    }

    // set the expression so far
    if (!expressionSoFar.isEmpty())
        expressionSoFar += " " + exprJoin + " ";
    expressionSoFar += exprName + " " + exprMatch + " " + value->text();
    expression->setText(expressionSoFar);

    // now reset the other UI elements.
    value->setText("");
    field->setCurrentIndex(0);
    match->setCurrentIndex(0);
    join->setCurrentIndex(0);
}

void FilterDialog::doneClicked()
{
    state = 1;
    hide();
    emit hidden();
}

void FilterDialog::showDialog()
{
    total = QContactIntersectionFilter();
    noFiltersYet = true;
    state = 0;
    expressionSoFar = "";

    // now reset the UI elements.
    value->setText("");
    field->setCurrentIndex(0);
    match->setCurrentIndex(0);
    join->setCurrentIndex(0);
    expression->setText("");

    show();
}
<|endoftext|>


<commit_before>/*
 *   Copyright 2012 Coherent Theory LLC
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "error.h"

#include <QObject>

using namespace Bodega;

class Error::Private
{
public:
    Private(Type t,
            const QString &errorId,
            const QString &title,
            const QString &descr)
      : code(NoCode),
        type(t),
        id(errorId),
        title(title),
        description(descr)
    {
    }

    Private(ServerCode c)
        : code(NoCode)
    {
        setServerCode(c);
    }

    Private(Type t)
        : code(NoCode),
          type(t)
    {
    }

    void setServerCode(ServerCode c);
    static void initServerCodeDict();

    ServerCode code;
    Type type;
    QString id;
    QString title;
    QString description;

    static QMap<QString, ServerCode> serverCodes;
};

QMap<QString, Error::ServerCode> Error::Private::serverCodes;

void Error::Private::initServerCodeDict()
{
    if (!serverCodes.isEmpty()) {
        return;
    }
    #define ADD_SERVER_CODE(CODE) serverCodes.insert(QLatin1String("" #CODE), CODE);
    ADD_SERVER_CODE(NoCode)
    ADD_SERVER_CODE(Connection)
    ADD_SERVER_CODE(Unknown)
    ADD_SERVER_CODE(Database)
    ADD_SERVER_CODE(Unauthorized)
    ADD_SERVER_CODE(MissingParameters)
    ADD_SERVER_CODE(NoMatch)
    ADD_SERVER_CODE(AccountInactive)
    ADD_SERVER_CODE(AccountExists)
    ADD_SERVER_CODE(PurchaseFailed)
    ADD_SERVER_CODE(MailerFailure)
    ADD_SERVER_CODE(AccountUpdateFailed)
    ADD_SERVER_CODE(EncryptionFailure)
    ADD_SERVER_CODE(PasswordTooShort)
    ADD_SERVER_CODE(Download)
    ADD_SERVER_CODE(AccessDenied)
    ADD_SERVER_CODE(RedeemCodeFailure)

    ADD_SERVER_CODE(PaymentMethodCreation)
    ADD_SERVER_CODE(PaymentMethodDeletion)
    ADD_SERVER_CODE(PaymentMethodDetails)
    ADD_SERVER_CODE(PaymentMethodMissing)
    ADD_SERVER_CODE(CustomerRetrieval)
    ADD_SERVER_CODE(CustomerDatabase)
    ADD_SERVER_CODE(CustomerCharge)
    ADD_SERVER_CODE(CustomerRefund)
    ADD_SERVER_CODE(ChargeNotRecorded)
    ADD_SERVER_CODE(NotEnoughPoints)
    ADD_SERVER_CODE(TooManyPoints)
    ADD_SERVER_CODE(CollectionExists)
    ADD_SERVER_CODE(AssetExists)
    ADD_SERVER_CODE(CardDeclined)
    ADD_SERVER_CODE(CardIncorrectNumber)
    ADD_SERVER_CODE(CardInvalidNumber)
    ADD_SERVER_CODE(CardInvalidExpiryMonth)
    ADD_SERVER_CODE(CardInvalidExpiryYear)
    ADD_SERVER_CODE(CardInvalidCVC)
    ADD_SERVER_CODE(CardExpired)
    ADD_SERVER_CODE(CardInvalidAmount)
    ADD_SERVER_CODE(CardDuplicateTransaction)
    ADD_SERVER_CODE(CardProcessingError)
    ADD_SERVER_CODE(PurchaseNotEnoughPoints)
    ADD_SERVER_CODE(PurchaseTooManyPoints)
}

void Error::Private::setServerCode(ServerCode c)
{
    code = c;
    type = Session;
    id = QLatin1String("session/") + QString::number(c);
    title = QObject::tr("Session Error");

    switch (code) {
        case Connection:
            description = QObject::tr("Connection failed.");
        break;
        case Database:
            description = QObject::tr("The add-ons database could not be reached.");
        break;
        case Unauthorized:
            description = QObject::tr("This account may not perform the requested action.");
        break;
        case MissingParameters:
            description = QObject::tr("Required information was missing from the request.");
        break;
        case NoMatch:
            description = QObject::tr("No matching records found.");
        break;
        case AccountInactive:
            description = QObject::tr("This account is not active.");
        break;
        case AccountExists:
            description = QObject::tr("An account for that email already exists.");
        break;
        case PurchaseFailed:
            description = QObject::tr("Could not purchase the requested item.");
        break;
        case MailerFailure:
            description = QObject::tr("Failed to send email.");
        break;
        case AccountUpdateFailed:
            description = QObject::tr("Failed to change account information.");
        break;
        case EncryptionFailure:
            description = QObject::tr("Encryption failed, please try again.");
        break;
        case PasswordTooShort:
            description = QObject::tr("The password is too short, please try again.");
        break;
        case Download:
            description = QObject::tr("Could not complete the download of the requested item.");
        break;
        case AccessDenied:
            description = QObject::tr("Could not complete the download of the requested item.");
        break;
        case RedeemCodeFailure:
            description = QObject::tr("The supplied points code was not valid.");
        break;

        case PaymentMethodCreation:
            title = QObject::tr("Payment Method Error");
            description = QObject::tr("Failed to update purchase method details.");
        break;
        case PaymentMethodDeletion:
            title = QObject::tr("Payment Method Error");
            description = QObject::tr("Failed to update purchase method details.");
        break;
        case PaymentMethodDetails:
            title = QObject::tr("Payment Method Error");
            description = QObject::tr("Failed to update purchase method details.");
        break;
        case PaymentMethodMissing:
            title = QObject::tr("Payment Method Error");
            description = QObject::tr("A valid payment method could not be found. Please add a payment method to your account.");
        break;
        case CustomerRetrieval:
            title = QObject::tr("Purchase Method Error");
            description = QObject::tr("No purchase method (e.g. credit card) information found.");
        break;
        case CustomerDatabase:
            description = QObject::tr("Could not locate the requested customer account.");
        break;
        case CustomerCharge:
        case CustomerRefund:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Unable to complete the purchase process. No charge was made to your card.");
        break;
        case ChargeNotRecorded:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Transaction was successful, but could not record the result on the account");
        break;
        case NotEnoughPoints:
            title = QObject::tr("Purchase Error");
            description = QObject::tr("Your account lacks enough points to make this purchase.");
        break;
        case TooManyPoints:
            title = QObject::tr("Purchase Error");
            description = QObject::tr("The requested amount of points exceeds the maximum purchase limit.");
        break;

        case CollectionExists:
            title = QObject::tr("Creation Error");
            description = QObject::tr("The collection already exists.");
        break;
        case AssetExists:
            title = QObject::tr("Creation Error");
            description = QObject::tr("The asset already exists.");
        break;

        case CardDeclined:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Your card has been declined. Please try another payment method");
        break;

        case CardIncorrectNumber:
        case CardInvalidNumber:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("The card number supplied is incorrect. Please check it and try again.");
        break;

        case CardInvalidExpiryMonth:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("The card expiry month supplied is incorrect.");
        break;

        case CardInvalidExpiryYear:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("The card expiry year supplied is incorrect.");
        break;

        case CardInvalidCVC:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("The card CVC supplied is incorrect.");
        break;

        case CardExpired:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Your card has expired. Please try another payment method.");
        break;

        case CardInvalidAmount:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("The purchase amount was invalid. Please try again.");
        break;

        case CardDuplicateTransaction:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("This transaction was already processed.");
        break;

        case CardProcessingError:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("A processing error occured when making the purchase. Please try again.");
        break;

        case PurchaseNotEnoughPoints:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Too few points were requested. A minimum of 500 points per purchase is required.");
        break;

        case PurchaseTooManyPoints:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Too many points were requested. Please purchase fewer points.");
        break;

        // NoCode, Unknown or out of bounds errors
        default:
            description = QObject::tr("An unknown error occurred.");
        break;
    }
}

Error::Error()
    : d(new Private(Session))
{
}

Error::Error(const Error &other)
    : d(new Private(*other.d))
{

}

Error::Error(ServerCode code)
    : d(new Private(code))
{
}

Error::Error(Type type, const QString &msg)
    : d(new Private(type, msg, msg, msg))
{
}

Error::Error(Type type,
             const QString &errorId,
             const QString &title,
             const QString &descr)
    : d(new Private(type, errorId, title, descr))
{
}

Error::~Error()
{
    delete d;
}

Error &Error::operator=(const Error &rhs)
{
    d->code = rhs.d->code;
    d->type = rhs.d->type;
    d->id = rhs.d->id;
    d->title = rhs.d->title;
    d->description = rhs.d->description;
    return *this;
}

Error::ServerCode Error::serverCode() const
{
    return d->code;
}

Error::Type Error::type() const
{
    return d->type;
}

QString Error::errorId() const
{
    return d->id;
}

QString Error::title() const
{
    return d->title;
}

QString Error::description() const
{
    return d->description;
}

Error::ServerCode Error::serverCodeId(const QString &string)
{
    Private::initServerCodeDict();
    if (Private::serverCodes.contains(string)) {
        return Private::serverCodes.value(string);
    }

    return Unknown;
}

<commit_msg>more friendly message<commit_after>/*
 *   Copyright 2012 Coherent Theory LLC
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "error.h"

#include <QObject>

using namespace Bodega;

class Error::Private
{
public:
    Private(Type t,
            const QString &errorId,
            const QString &title,
            const QString &descr)
      : code(NoCode),
        type(t),
        id(errorId),
        title(title),
        description(descr)
    {
    }

    Private(ServerCode c)
        : code(NoCode)
    {
        setServerCode(c);
    }

    Private(Type t)
        : code(NoCode),
          type(t)
    {
    }

    void setServerCode(ServerCode c);
    static void initServerCodeDict();

    ServerCode code;
    Type type;
    QString id;
    QString title;
    QString description;

    static QMap<QString, ServerCode> serverCodes;
};

QMap<QString, Error::ServerCode> Error::Private::serverCodes;

void Error::Private::initServerCodeDict()
{
    if (!serverCodes.isEmpty()) {
        return;
    }
    #define ADD_SERVER_CODE(CODE) serverCodes.insert(QLatin1String("" #CODE), CODE);
    ADD_SERVER_CODE(NoCode)
    ADD_SERVER_CODE(Connection)
    ADD_SERVER_CODE(Unknown)
    ADD_SERVER_CODE(Database)
    ADD_SERVER_CODE(Unauthorized)
    ADD_SERVER_CODE(MissingParameters)
    ADD_SERVER_CODE(NoMatch)
    ADD_SERVER_CODE(AccountInactive)
    ADD_SERVER_CODE(AccountExists)
    ADD_SERVER_CODE(PurchaseFailed)
    ADD_SERVER_CODE(MailerFailure)
    ADD_SERVER_CODE(AccountUpdateFailed)
    ADD_SERVER_CODE(EncryptionFailure)
    ADD_SERVER_CODE(PasswordTooShort)
    ADD_SERVER_CODE(Download)
    ADD_SERVER_CODE(AccessDenied)
    ADD_SERVER_CODE(RedeemCodeFailure)

    ADD_SERVER_CODE(PaymentMethodCreation)
    ADD_SERVER_CODE(PaymentMethodDeletion)
    ADD_SERVER_CODE(PaymentMethodDetails)
    ADD_SERVER_CODE(PaymentMethodMissing)
    ADD_SERVER_CODE(CustomerRetrieval)
    ADD_SERVER_CODE(CustomerDatabase)
    ADD_SERVER_CODE(CustomerCharge)
    ADD_SERVER_CODE(CustomerRefund)
    ADD_SERVER_CODE(ChargeNotRecorded)
    ADD_SERVER_CODE(NotEnoughPoints)
    ADD_SERVER_CODE(TooManyPoints)
    ADD_SERVER_CODE(CollectionExists)
    ADD_SERVER_CODE(AssetExists)
    ADD_SERVER_CODE(CardDeclined)
    ADD_SERVER_CODE(CardIncorrectNumber)
    ADD_SERVER_CODE(CardInvalidNumber)
    ADD_SERVER_CODE(CardInvalidExpiryMonth)
    ADD_SERVER_CODE(CardInvalidExpiryYear)
    ADD_SERVER_CODE(CardInvalidCVC)
    ADD_SERVER_CODE(CardExpired)
    ADD_SERVER_CODE(CardInvalidAmount)
    ADD_SERVER_CODE(CardDuplicateTransaction)
    ADD_SERVER_CODE(CardProcessingError)
    ADD_SERVER_CODE(PurchaseNotEnoughPoints)
    ADD_SERVER_CODE(PurchaseTooManyPoints)
}

void Error::Private::setServerCode(ServerCode c)
{
    code = c;
    type = Session;
    id = QLatin1String("session/") + QString::number(c);
    title = QObject::tr("Session Error");

    switch (code) {
        case Connection:
            description = QObject::tr("Connection failed.");
        break;
        case Database:
            description = QObject::tr("The add-ons database could not be reached.");
        break;
        case Unauthorized:
            description = QObject::tr("This account may not perform the requested action.");
        break;
        case MissingParameters:
            description = QObject::tr("Required information was missing from the request.");
        break;
        case NoMatch:
            description = QObject::tr("Wrong user name or password.");
        break;
        case AccountInactive:
            description = QObject::tr("This account is not active.");
        break;
        case AccountExists:
            description = QObject::tr("An account for that email already exists.");
        break;
        case PurchaseFailed:
            description = QObject::tr("Could not purchase the requested item.");
        break;
        case MailerFailure:
            description = QObject::tr("Failed to send email.");
        break;
        case AccountUpdateFailed:
            description = QObject::tr("Failed to change account information.");
        break;
        case EncryptionFailure:
            description = QObject::tr("Encryption failed, please try again.");
        break;
        case PasswordTooShort:
            description = QObject::tr("The password is too short, please try again.");
        break;
        case Download:
            description = QObject::tr("Could not complete the download of the requested item.");
        break;
        case AccessDenied:
            description = QObject::tr("Could not complete the download of the requested item.");
        break;
        case RedeemCodeFailure:
            description = QObject::tr("The supplied points code was not valid.");
        break;

        case PaymentMethodCreation:
            title = QObject::tr("Payment Method Error");
            description = QObject::tr("Failed to update purchase method details.");
        break;
        case PaymentMethodDeletion:
            title = QObject::tr("Payment Method Error");
            description = QObject::tr("Failed to update purchase method details.");
        break;
        case PaymentMethodDetails:
            title = QObject::tr("Payment Method Error");
            description = QObject::tr("Failed to update purchase method details.");
        break;
        case PaymentMethodMissing:
            title = QObject::tr("Payment Method Error");
            description = QObject::tr("A valid payment method could not be found. Please add a payment method to your account.");
        break;
        case CustomerRetrieval:
            title = QObject::tr("Purchase Method Error");
            description = QObject::tr("No purchase method (e.g. credit card) information found.");
        break;
        case CustomerDatabase:
            description = QObject::tr("Could not locate the requested customer account.");
        break;
        case CustomerCharge:
        case CustomerRefund:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Unable to complete the purchase process. No charge was made to your card.");
        break;
        case ChargeNotRecorded:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Transaction was successful, but could not record the result on the account");
        break;
        case NotEnoughPoints:
            title = QObject::tr("Purchase Error");
            description = QObject::tr("Your account lacks enough points to make this purchase.");
        break;
        case TooManyPoints:
            title = QObject::tr("Purchase Error");
            description = QObject::tr("The requested amount of points exceeds the maximum purchase limit.");
        break;

        case CollectionExists:
            title = QObject::tr("Creation Error");
            description = QObject::tr("The collection already exists.");
        break;
        case AssetExists:
            title = QObject::tr("Creation Error");
            description = QObject::tr("The asset already exists.");
        break;

        case CardDeclined:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Your card has been declined. Please try another payment method");
        break;

        case CardIncorrectNumber:
        case CardInvalidNumber:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("The card number supplied is incorrect. Please check it and try again.");
        break;

        case CardInvalidExpiryMonth:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("The card expiry month supplied is incorrect.");
        break;

        case CardInvalidExpiryYear:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("The card expiry year supplied is incorrect.");
        break;

        case CardInvalidCVC:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("The card CVC supplied is incorrect.");
        break;

        case CardExpired:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Your card has expired. Please try another payment method.");
        break;

        case CardInvalidAmount:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("The purchase amount was invalid. Please try again.");
        break;

        case CardDuplicateTransaction:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("This transaction was already processed.");
        break;

        case CardProcessingError:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("A processing error occured when making the purchase. Please try again.");
        break;

        case PurchaseNotEnoughPoints:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Too few points were requested. A minimum of 500 points per purchase is required.");
        break;

        case PurchaseTooManyPoints:
            title = QObject::tr("Transaction Error");
            description = QObject::tr("Too many points were requested. Please purchase fewer points.");
        break;

        // NoCode, Unknown or out of bounds errors
        default:
            description = QObject::tr("An unknown error occurred.");
        break;
    }
}

Error::Error()
    : d(new Private(Session))
{
}

Error::Error(const Error &other)
    : d(new Private(*other.d))
{

}

Error::Error(ServerCode code)
    : d(new Private(code))
{
}

Error::Error(Type type, const QString &msg)
    : d(new Private(type, msg, msg, msg))
{
}

Error::Error(Type type,
             const QString &errorId,
             const QString &title,
             const QString &descr)
    : d(new Private(type, errorId, title, descr))
{
}

Error::~Error()
{
    delete d;
}

Error &Error::operator=(const Error &rhs)
{
    d->code = rhs.d->code;
    d->type = rhs.d->type;
    d->id = rhs.d->id;
    d->title = rhs.d->title;
    d->description = rhs.d->description;
    return *this;
}

Error::ServerCode Error::serverCode() const
{
    return d->code;
}

Error::Type Error::type() const
{
    return d->type;
}

QString Error::errorId() const
{
    return d->id;
}

QString Error::title() const
{
    return d->title;
}

QString Error::description() const
{
    return d->description;
}

Error::ServerCode Error::serverCodeId(const QString &string)
{
    Private::initServerCodeDict();
    if (Private::serverCodes.contains(string)) {
        return Private::serverCodes.value(string);
    }

    return Unknown;
}

<|endoftext|>