<commit_before>/* Copyright (c) 2009-2015 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <assert.h>

#include <iostream>
#include <fstream>

#include "ClusterMetrics.h"
#include "Context.h"
#include "Cycles.h"
#include "Dispatch.h"
#include "ShortMacros.h"
#include "Crc32C.h"
#include "ObjectFinder.h"
#include "OptionParser.h"
#include "RamCloud.h"
#include "Tub.h"
#include "IndexLookup.h"
#include "TableEnumerator.h"

using namespace RAMCloud;

/**
 * A utility for splitting table images generated by the TableDownloader
 * into chunks of equal size (measured in RAMCloud objects). Once split, those
 * parts can be uploaded in parallel by the TableUploader.
 */
int
main(int argc, char *argv[])
try
{
  string imageFilePath;
  long objectsPerFile;
  string outputDir;
  string splitSuffixFormat;

  // Set line buffering for stdout so that printf's and log messages
  // interleave properly.
  setvbuf(stdout, NULL, _IOLBF, 1024);

  // Need external context to set log levels with OptionParser
  Context context(false);

  OptionsDescription clientOptions("TableImageSplitter");
  clientOptions.add_options()

    ("imageFile",
     ProgramOptions::value<string>(&imageFilePath),
     "Path to the image file to split.")
    ("objectsPerFile",
     ProgramOptions::value<long>(&objectsPerFile),
     "How many objects to pack into a partition.")
    ("outputDir",
     ProgramOptions::value<string>(&outputDir),
     "Directory to write split files.")
    ("splitSuffixFormat",
     ProgramOptions::value<string>(&splitSuffixFormat)->
         default_value(".part%04d"),
     "Format string of the suffix to use for partitions. Must contain "
         "exactly one %d. [default: \".part%04d\"].");

  OptionParser optionParser(clientOptions, argc, argv);

  printf("TableImageSplitter: {imageFile: %s, objectsPerFile: %u, "
      "outputDir: %s, splitSuffixFormat: %s}\n", imageFilePath.c_str(),
      objectsPerFile, outputDir.c_str(), splitSuffixFormat.c_str());

  // Open image file for splitting.
  std::ifstream inFile;
  inFile.open(imageFilePath.c_str(), std::ios::binary);

  size_t lastSlashIndex = imageFilePath.find_last_of("/");
  string imageFileName;
  if (lastSlashIndex != string::npos)
    imageFileName = imageFilePath.substr(lastSlashIndex + 1);
  else
    imageFileName = imageFilePath;

  long partitionCount = 0; // How many partitions we've created so far.
  long objCount = 0; // How many objects are in the current partition.
  long totalObjCount = 0; // How many objects have we copied in total.
  long byteCount = 0; // How many total bytes have we copied so far.

  // Open initial output file for first partition.
  char *outFileName;
  asprintf(&outFileName,
      (outputDir + "/" + imageFileName + splitSuffixFormat).c_str(),
      partitionCount);
  std::ofstream outFile;
  outFile.open(outFileName, std::ios::binary);
  printf("Creating %s... ", outFileName);
  free(outFileName);

  // Read the imagefile until there are no more objects left in the file.
  char lenBuffer[sizeof(uint32_t)];
  while(inFile.read(lenBuffer, sizeof(lenBuffer))) {
    uint32_t keyLength = *((uint32_t*) lenBuffer);
    char keyBuffer[keyLength];
    inFile.read(keyBuffer, keyLength);

    inFile.read(lenBuffer, sizeof(lenBuffer));
    uint32_t dataLength = *((uint32_t*) lenBuffer);
    char dataBuffer[dataLength];
    inFile.read(dataBuffer, dataLength);

    // Copy object to output file.
    outFile.write((char*) &keyLength, sizeof(uint32_t));
    outFile.write((char*) keyBuffer, keyLength);
    outFile.write((char*) &dataLength, sizeof(uint32_t));
    outFile.write((char*) dataBuffer, dataLength);

    objCount++;
    totalObjCount++;
    byteCount += keyLength + dataLength;

    // If we've filled up the partition, close it and start a new one.
    if (objCount == objectsPerFile) {
      outFile.close();
      partitionCount++;
      printf("Done\n");

      asprintf(&outFileName,
          (outputDir + "/" + imageFileName + splitSuffixFormat).c_str(),
          partitionCount);
      outFile.open(outFileName, std::ios::binary);
      printf("Creating %s... ", outFileName);
      free(outFileName);

      objCount = 0;
    }
  }

  outFile.close();
  partitionCount++;
  printf("Done\n");

  inFile.close();

  printf("Split table image into %u partitions. Total objects: %u. Total "
      "bytes: %u\n", partitionCount, totalObjCount, byteCount);

  return 0;
} catch (Exception& e) {
    fprintf(stderr, "Exception: %s\n", e.str().c_str());
    return 1;
}

<commit_msg>Added bytePerFile opt to TableImageSplitter.<commit_after>/* Copyright (c) 2009-2015 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <assert.h>

#include <iostream>
#include <fstream>

#include "ClusterMetrics.h"
#include "Context.h"
#include "Cycles.h"
#include "Dispatch.h"
#include "ShortMacros.h"
#include "Crc32C.h"
#include "ObjectFinder.h"
#include "OptionParser.h"
#include "RamCloud.h"
#include "Tub.h"
#include "IndexLookup.h"
#include "TableEnumerator.h"

using namespace RAMCloud;

/**
 * A utility for splitting table images generated by the TableDownloader
 * into chunks of equal size (measured in RAMCloud objects). Once split, those
 * parts can be uploaded in parallel by the TableUploader.
 */
int
main(int argc, char *argv[])
try
{
  string imageFilePath;
  long objectsPerFile;
  long bytesPerFile;
  string outputDir;
  string splitSuffixFormat;

  // Set line buffering for stdout so that printf's and log messages
  // interleave properly.
  setvbuf(stdout, NULL, _IOLBF, 1024);

  // Need external context to set log levels with OptionParser
  Context context(false);

  OptionsDescription clientOptions("TableImageSplitter");
  clientOptions.add_options()

    ("imageFile",
     ProgramOptions::value<string>(&imageFilePath),
     "Path to the image file to split.")
    ("objectsPerFile",
     ProgramOptions::value<long>(&objectsPerFile)->default_value(0),
     "How many objects to pack into a partition.")
    ("bytesPerFile",
     ProgramOptions::value<long>(&bytesPerFile)->default_value(0),
     "How many bytes to pack into a partition.")
    ("outputDir",
     ProgramOptions::value<string>(&outputDir),
     "Directory to write split files.")
    ("splitSuffixFormat",
     ProgramOptions::value<string>(&splitSuffixFormat)->
         default_value(".part%04d"),
     "Format string of the suffix to use for partitions. Must contain "
         "exactly one %d. [default: \".part%04d\"].");

  OptionParser optionParser(clientOptions, argc, argv);

  printf("TableImageSplitter: {imageFile: %s, objectsPerFile: %lu, "
      "bytesPerFile: %lu, outputDir: %s, splitSuffixFormat: %s}\n",
      imageFilePath.c_str(), objectsPerFile, bytesPerFile, outputDir.c_str(),
      splitSuffixFormat.c_str());

  // Open image file for splitting.
  std::ifstream inFile;
  inFile.open(imageFilePath.c_str(), std::ios::binary);

  size_t lastSlashIndex = imageFilePath.find_last_of("/");
  string imageFileName;
  if (lastSlashIndex != string::npos)
    imageFileName = imageFilePath.substr(lastSlashIndex + 1);
  else
    imageFileName = imageFilePath;

  long partitionCount = 0; // How many partitions we've created so far.
  long objCount = 0; // How many objects are in the current partition.
  long totalObjCount = 0; // How many objects have we copied in total.
  long byteCount = 0; // How many bytes are in the current partition.
  long totalObjByteCount = 0; // How many total bytes have we copied so far.

  // Open initial output file for first partition.
  char *outFileName;
  asprintf(&outFileName,
      (outputDir + "/" + imageFileName + splitSuffixFormat).c_str(),
      partitionCount);
  std::ofstream outFile;
  outFile.open(outFileName, std::ios::binary);
  printf("Creating %s... ", outFileName);
  free(outFileName);

  // Read the imagefile until there are no more objects left in the file.
  char lenBuffer[sizeof(uint32_t)];
  while(inFile.read(lenBuffer, sizeof(lenBuffer))) {
    uint32_t keyLength = *((uint32_t*) lenBuffer);
    char keyBuffer[keyLength];
    inFile.read(keyBuffer, keyLength);

    inFile.read(lenBuffer, sizeof(lenBuffer));
    uint32_t dataLength = *((uint32_t*) lenBuffer);
    char dataBuffer[dataLength];
    inFile.read(dataBuffer, dataLength);

    // Copy object to output file.
    outFile.write((char*) &keyLength, sizeof(uint32_t));
    outFile.write((char*) keyBuffer, keyLength);
    outFile.write((char*) &dataLength, sizeof(uint32_t));
    outFile.write((char*) dataBuffer, dataLength);

    objCount++;
    totalObjCount++;
    byteCount += sizeof(uint32_t) + keyLength + sizeof(uint32_t) + dataLength;
    totalObjByteCount += keyLength + dataLength;

    // If we've filled up the partition, close it and start a new one.
    if (objectsPerFile > 0) {
      if (objCount == objectsPerFile) {
        outFile.close();
        partitionCount++;
        printf("Done\n");

        asprintf(&outFileName,
            (outputDir + "/" + imageFileName + splitSuffixFormat).c_str(),
            partitionCount);
        outFile.open(outFileName, std::ios::binary);
        printf("Creating %s... ", outFileName);
        free(outFileName);

        objCount = 0;
        byteCount = 0;
      }
    } else {
      if (byteCount > bytesPerFile) {
        outFile.close();
        partitionCount++;
        printf("Done\n");

        asprintf(&outFileName,
            (outputDir + "/" + imageFileName + splitSuffixFormat).c_str(),
            partitionCount);
        outFile.open(outFileName, std::ios::binary);
        printf("Creating %s... ", outFileName);
        free(outFileName);

        objCount = 0;
        byteCount = 0;
      }
    }
  }

  outFile.close();
  partitionCount++;
  printf("Done\n");

  inFile.close();

  printf("Split table image into %lu partitions. Total objects: %lu. Total "
      "bytes: %lu\n", partitionCount, totalObjCount, totalObjByteCount);

  return 0;
} catch (Exception& e) {
    fprintf(stderr, "Exception: %s\n", e.str().c_str());
    return 1;
}

<|endoftext|>


<commit_before>#include "SharedMessagePool.hpp"
#include "Statistics.hpp"
#include "ConditionVariable.hpp"
#include <stack>

DEFINE_int64(shared_pool_size, 1L << 20, "Size (in bytes) of global SharedMessagePool (on each Core)");
DEFINE_int64(shared_pool_max, -1, "Maximum number of shared pools allowed to be allocated (per core).");

GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, shared_message_pools_allocated, 0);

namespace Grappa {

  SharedMessagePool * shared_pool = nullptr;
  std::stack<SharedMessagePool*> unused_pools;
  ConditionVariable blocked_senders;

  void init_shared_pool() {
    void * p = impl::locale_shared_memory.allocate_aligned(sizeof(SharedMessagePool), 8);
    shared_pool = new (p) SharedMessagePool(FLAGS_shared_pool_size);
    shared_message_pools_allocated++;
    VLOG(3) << "initialized shared_pool @ " << shared_pool << ", buf:" << (void*)shared_pool->buffer;
  }

  void* SharedMessagePool::allocate(size_t size) {
    VLOG(5) << "allocating on shared pool " << this;
    CHECK_EQ(this, shared_pool) << "not allocating from global shared_pool!";

    if (this->remaining() < size) {
      CHECK(size <= this->buffer_size) << "Pool (" << this->buffer_size << ") is not large enough to allocate " << size << " bytes.";
      VLOG(3) << "MessagePool full (" << this << ", to_send:"<< this->to_send << "), finding a new one;    completions_received:" << completions_received << ", allocated_count:" << allocated_count;

      // first try and find one from the unused_pools pool
      if (unused_pools.size() > 0) { pop_pool:
        shared_pool = unused_pools.top();
        VLOG(4) << "found pool @ " << shared_pool << " allocated:" << shared_pool->allocated << "/" << shared_pool->buffer_size << ", count=" << allocated_count << " @ " << this;
        unused_pools.pop();
      } else if (!global_scheduler.in_no_switch_region() && FLAGS_shared_pool_max > 0 &&
          shared_message_pools_allocated >= FLAGS_shared_pool_max-1) {
        Grappa::wait(&blocked_senders);
        if (this == shared_pool) {
          CHECK_GT(unused_pools.size(), 0);
          goto pop_pool;
        } // else should be able to just fall through and go on our merry way
        // CHECK(unused_pools.size() > 0 || shared_pool->remaining() > size);
      } else {
        // allocate a new one, have the old one delete itself when all previous have been sent
        void * p = impl::locale_shared_memory.allocate_aligned(sizeof(SharedMessagePool), 8);
        shared_pool = new (p) SharedMessagePool(this->buffer_size);
        shared_message_pools_allocated++;
        VLOG(4) << "created new shared_pool @ " << shared_pool << ", buf:" << shared_pool->buffer;
      }

      this->start_emptying(); // start working on freeing up the previous one

      return shared_pool->allocate(size); // actually satisfy the allocation request
    } else {
      allocated_count++;
      this->to_send++;
      return PoolAllocator<impl::MessageBase>::allocate(size);
      // return impl::MessagePoolBase::allocate(size);
    }
  }

  void SharedMessagePool::start_emptying() {
    emptying = true;
    // CHECK_GT(to_send, 0);
    if (to_send == 0 && emptying) { on_empty(); }
  }

  void SharedMessagePool::message_sent(impl::MessageBase* m) {
    CHECK( reinterpret_cast<char*>(m) >= this->buffer && reinterpret_cast<char*>(m)+m->size() <= this->buffer+this->buffer_size )
        << "message is outside this pool!! message(" << m << ", extra:" << m->pool << "), "
        << "pool(" << this << ", buf:" << (void*)this->buffer << ", size:" << this->buffer_size << ")";
    to_send--;
    completions_received++;
    if (to_send == 0 && emptying) {
      VLOG(3) << "empty! so put back on unused stack message(" << m << ", is_sent_:" << m->is_sent_ << ")";
      on_empty();
    }
  }

  void SharedMessagePool::on_empty() {

    VLOG(3) << "empty and emptying, to_send:"<< to_send << ", allocated:" << allocated << "/" << buffer_size << " @ " << this << ", buf:" << (void*)buffer << "  completions_received:" << completions_received << ", allocated_count:" << allocated_count;

    // verify everything sent
    this->iterate([](impl::MessageBase* m) {
      if (!m->is_sent_ || !m->is_delivered_ || !m->is_enqueued_) {
        VLOG(1) << "!! message(" << m << ", is_sent_:" << m->is_sent_ << ", is_delivered_:" << m->is_delivered_ << ", m->is_enqueued_:" << m->is_enqueued_ << ", extra:" << m->pool << ")";
      }
    });

    this->reset();

    memset(buffer, (0x11*locale_mycore()) | 0xf0, buffer_size); // poison

    unused_pools.push(this);
    broadcast(&blocked_senders);
  }

} // namespace Grappa
<commit_msg>Add note about how shared_pool_max works.<commit_after>#include "SharedMessagePool.hpp"
#include "Statistics.hpp"
#include "ConditionVariable.hpp"
#include <stack>

DEFINE_int64(shared_pool_size, 1L << 20, "Size (in bytes) of global SharedMessagePool (on each Core)");

/// Note: max is enforced only for blockable callers, and is enforced early to avoid callers
/// that cannot block (callers from message handlers) to have a greater chance of proceeding.
DEFINE_int64(shared_pool_max, -1, "Maximum number of shared pools allowed to be allocated (per core).");

GRAPPA_DEFINE_STAT(SimpleStatistic<uint64_t>, shared_message_pools_allocated, 0);

namespace Grappa {

  SharedMessagePool * shared_pool = nullptr;
  std::stack<SharedMessagePool*> unused_pools;
  ConditionVariable blocked_senders;

  void init_shared_pool() {
    void * p = impl::locale_shared_memory.allocate_aligned(sizeof(SharedMessagePool), 8);
    shared_pool = new (p) SharedMessagePool(FLAGS_shared_pool_size);
    shared_message_pools_allocated++;
    VLOG(3) << "initialized shared_pool @ " << shared_pool << ", buf:" << (void*)shared_pool->buffer;
  }

  void* SharedMessagePool::allocate(size_t size) {
    VLOG(5) << "allocating on shared pool " << this;
    CHECK_EQ(this, shared_pool) << "not allocating from global shared_pool!";

    if (this->remaining() < size) {
      CHECK(size <= this->buffer_size) << "Pool (" << this->buffer_size << ") is not large enough to allocate " << size << " bytes.";
      VLOG(3) << "MessagePool full (" << this << ", to_send:"<< this->to_send << "), finding a new one;    completions_received:" << completions_received << ", allocated_count:" << allocated_count;

      // first try and find one from the unused_pools pool
      if (unused_pools.size() > 0) { pop_pool:
        shared_pool = unused_pools.top();
        VLOG(4) << "found pool @ " << shared_pool << " allocated:" << shared_pool->allocated << "/" << shared_pool->buffer_size << ", count=" << allocated_count << " @ " << this;
        unused_pools.pop();
      } else if (!global_scheduler.in_no_switch_region() && FLAGS_shared_pool_max > 0 &&
          shared_message_pools_allocated >= FLAGS_shared_pool_max-1) {
        Grappa::wait(&blocked_senders);
        if (this == shared_pool) {
          CHECK_GT(unused_pools.size(), 0);
          goto pop_pool;
        } // else should be able to just fall through and go on our merry way
        // CHECK(unused_pools.size() > 0 || shared_pool->remaining() > size);
      } else {
        // allocate a new one, have the old one delete itself when all previous have been sent
        void * p = impl::locale_shared_memory.allocate_aligned(sizeof(SharedMessagePool), 8);
        shared_pool = new (p) SharedMessagePool(this->buffer_size);
        shared_message_pools_allocated++;
        VLOG(4) << "created new shared_pool @ " << shared_pool << ", buf:" << shared_pool->buffer;
      }

      this->start_emptying(); // start working on freeing up the previous one

      return shared_pool->allocate(size); // actually satisfy the allocation request
    } else {
      allocated_count++;
      this->to_send++;
      return PoolAllocator<impl::MessageBase>::allocate(size);
      // return impl::MessagePoolBase::allocate(size);
    }
  }

  void SharedMessagePool::start_emptying() {
    emptying = true;
    // CHECK_GT(to_send, 0);
    if (to_send == 0 && emptying) { on_empty(); }
  }

  void SharedMessagePool::message_sent(impl::MessageBase* m) {
    CHECK( reinterpret_cast<char*>(m) >= this->buffer && reinterpret_cast<char*>(m)+m->size() <= this->buffer+this->buffer_size )
        << "message is outside this pool!! message(" << m << ", extra:" << m->pool << "), "
        << "pool(" << this << ", buf:" << (void*)this->buffer << ", size:" << this->buffer_size << ")";
    to_send--;
    completions_received++;
    if (to_send == 0 && emptying) {
      VLOG(3) << "empty! so put back on unused stack message(" << m << ", is_sent_:" << m->is_sent_ << ")";
      on_empty();
    }
  }

  void SharedMessagePool::on_empty() {

    VLOG(3) << "empty and emptying, to_send:"<< to_send << ", allocated:" << allocated << "/" << buffer_size << " @ " << this << ", buf:" << (void*)buffer << "  completions_received:" << completions_received << ", allocated_count:" << allocated_count;

    // verify everything sent
    this->iterate([](impl::MessageBase* m) {
      if (!m->is_sent_ || !m->is_delivered_ || !m->is_enqueued_) {
        VLOG(1) << "!! message(" << m << ", is_sent_:" << m->is_sent_ << ", is_delivered_:" << m->is_delivered_ << ", m->is_enqueued_:" << m->is_enqueued_ << ", extra:" << m->pool << ")";
      }
    });

    this->reset();

    memset(buffer, (0x11*locale_mycore()) | 0xf0, buffer_size); // poison

    unused_pools.push(this);
    broadcast(&blocked_senders);
  }

} // namespace Grappa
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <math.h>
#include "pow.h"

#include "chain.h"
#include "chainparams.h"
#include "primitives/block.h"
#include "uint256.h"
#include "util.h"

unsigned int static KimotoGravityWell(const CBlockIndex* pindexLast, const CBlockHeader *pblock, uint64_t TargetBlocksSpacingSeconds, uint64_t PastBlocksMin, uint64_t PastBlocksMax) {
    /* current difficulty formula, megacoin - kimoto gravity well */
    const CBlockIndex  *BlockLastSolved             = pindexLast;
    const CBlockIndex  *BlockReading                = pindexLast;
    const CBlockHeader *BlockCreating               = pblock;
                        BlockCreating               = BlockCreating;
    uint64_t              PastBlocksMass              = 0;
    int64_t               PastRateActualSeconds       = 0;
    int64_t               PastRateTargetSeconds       = 0;
    int64_t               LatestBlockTime             = BlockLastSolved->GetBlockTime();
    double              PastRateAdjustmentRatio     = double(1);
    uint256             PastDifficultyAverage;
    uint256             PastDifficultyAveragePrev;
    double              EventHorizonDeviation;
    double              EventHorizonDeviationFast;
    double              EventHorizonDeviationSlow;
    const uint256 &bnProofOfWorkLimit = Params().ProofOfWorkLimit();

    if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || (uint64_t)BlockLastSolved->nHeight < PastBlocksMin) { return bnProofOfWorkLimit.GetCompact(); }

    for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
        if (PastBlocksMax > 0 && i > PastBlocksMax) { break; }
        PastBlocksMass++;

        if (i == 1) { PastDifficultyAverage.SetCompact(BlockReading->nBits); }
        else        { PastDifficultyAverage = ((uint256().SetCompact(BlockReading->nBits) - PastDifficultyAveragePrev) / i) + PastDifficultyAveragePrev; }
        PastDifficultyAveragePrev = PastDifficultyAverage;

        if (LatestBlockTime < BlockReading->GetBlockTime()) { LatestBlockTime = BlockReading->GetBlockTime(); }
        PastRateActualSeconds           = LatestBlockTime - BlockReading->GetBlockTime();
        PastRateTargetSeconds           = TargetBlocksSpacingSeconds * PastBlocksMass;
        PastRateAdjustmentRatio         = double(1);
        if (PastRateActualSeconds < 1) { PastRateActualSeconds = 1; }
        if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) {
        PastRateAdjustmentRatio         = double(PastRateTargetSeconds) / double(PastRateActualSeconds);
        }
        EventHorizonDeviation           = 1 + (0.7084 * pow((double(PastBlocksMass)/double(9)), -1.228));
        EventHorizonDeviationFast       = EventHorizonDeviation;
        EventHorizonDeviationSlow       = 1 / EventHorizonDeviation;

        if (PastBlocksMass >= PastBlocksMin) {
            if ((PastRateAdjustmentRatio <= EventHorizonDeviationSlow) || (PastRateAdjustmentRatio >= EventHorizonDeviationFast)) { assert(BlockReading); break; }
        }
        if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
        BlockReading = BlockReading->pprev;
    }

    uint256 bnNew(PastDifficultyAverage);
    if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) {
        bnNew *= PastRateActualSeconds;
        bnNew /= PastRateTargetSeconds;
    }
    if (bnNew > bnProofOfWorkLimit) { bnNew = bnProofOfWorkLimit; }

    /// debug print
    LogPrintf("Difficulty Retarget - BOB's Wormh0le (KGW)\n");
    LogPrintf("PastRateAdjustmentRatio = %g\n", PastRateAdjustmentRatio);
    LogPrintf("Before: %08x  %s\n", BlockLastSolved->nBits, uint256().SetCompact(BlockLastSolved->nBits).ToString().c_str());
    LogPrintf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString().c_str());

    return bnNew.GetCompact();
}

unsigned int static GetNextWorkRequired_V2(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    static const int64_t  BlocksTargetSpacing         = 10 * 60; // 10 minutes
    unsigned int        TimeDaySeconds              = 60 * 60 * 24;
    int64_t               PastSecondsMin              = TimeDaySeconds * 0.0625;
    int64_t               PastSecondsMax              = TimeDaySeconds * 1.75;
    uint64_t              PastBlocksMin               = PastSecondsMin / BlocksTargetSpacing;
    uint64_t              PastBlocksMax               = PastSecondsMax / BlocksTargetSpacing;

    return KimotoGravityWell(pindexLast, pblock, BlocksTargetSpacing, PastBlocksMin, PastBlocksMax);
}

unsigned int GetNextWorkRequired_V1(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();

    // Genesis block
    if (pindexLast == NULL)
        return nProofOfWorkLimit;

    // Only change once per interval
    if ((pindexLast->nHeight+1) % Params().Interval() != 0)
    {
        if (Params().AllowMinDifficultyBlocks())
        {
            // Special difficulty rule for testnet:
            // If the new block's timestamp is more than 2* 10 minutes
            // then allow mining of a min-difficulty block.
            if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + Params().TargetSpacing()*2)
                return nProofOfWorkLimit;
            else
            {
                // Return the last non-special-min-difficulty-rules-block
                const CBlockIndex* pindex = pindexLast;
                while (pindex->pprev && pindex->nHeight % Params().Interval() != 0 && pindex->nBits == nProofOfWorkLimit)
                    pindex = pindex->pprev;
                return pindex->nBits;
            }
        }
        return pindexLast->nBits;
    }

    // Go back by what we want to be 14 days worth of blocks
    const CBlockIndex* pindexFirst = pindexLast;
    for (int i = 0; pindexFirst && i < Params().Interval()-1; i++)
        pindexFirst = pindexFirst->pprev;
    assert(pindexFirst);

    // Limit adjustment step
    int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
    LogPrintf("  nActualTimespan = %d  before bounds\n", nActualTimespan);
    if (nActualTimespan < Params().TargetTimespan()/4)
        nActualTimespan = Params().TargetTimespan()/4;
    if (nActualTimespan > Params().TargetTimespan()*4)
        nActualTimespan = Params().TargetTimespan()*4;

    // Retarget
    uint256 bnNew;
    uint256 bnOld;
    bnNew.SetCompact(pindexLast->nBits);
    bnOld = bnNew;
    bnNew *= nActualTimespan;
    bnNew /= Params().TargetTimespan();

    if (bnNew > Params().ProofOfWorkLimit())
        bnNew = Params().ProofOfWorkLimit();

    /// debug print
    LogPrintf("GetNextWorkRequired RETARGET\n");
    LogPrintf("Params().TargetTimespan() = %d    nActualTimespan = %d\n", Params().TargetTimespan(), nActualTimespan);
    LogPrintf("Before: %08x  %s\n", pindexLast->nBits, bnOld.ToString());
    LogPrintf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString());

    return bnNew.GetCompact();
}

unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    int DiffMode = 1;
    if (Params().AllowMinDifficultyBlocks()) {
    //    if (pindexLast->nHeight+1 >= 50) { DiffMode = 2; }
    }
    else {
        if (pindexLast->nHeight+1 >= 13579) { DiffMode = 2; } // KGW @ Block 13579
    }

    if      (DiffMode == 1) { return GetNextWorkRequired_V1(pindexLast, pblock); }
    else if (DiffMode == 2) { return GetNextWorkRequired_V2(pindexLast, pblock); }
    return GetNextWorkRequired_V2(pindexLast, pblock);
}

bool CheckProofOfWork(uint256 hash, unsigned int nBits)
{
    bool fNegative;
    bool fOverflow;
    uint256 bnTarget;

    if(hash==HASHGENESISBLOCKPOW) //ignore genesis block
    {
        return true;
    }

    if (Params().SkipProofOfWorkCheck())
       return true;

    bnTarget.SetCompact(nBits, &fNegative, &fOverflow);

    // Check range
    if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit())
        return error("CheckProofOfWork() : nBits below minimum work");

    // Check proof of work matches claimed amount
    if (hash > bnTarget)
        return error("CheckProofOfWork() : hash doesn't match nBits");

    return true;
}

uint256 GetBlockProof(const CBlockIndex& block)
{
    uint256 bnTarget;
    bool fNegative;
    bool fOverflow;
    bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
    if (fNegative || fOverflow || bnTarget == 0)
        return 0;
    // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
    // as it's too large for a uint256. However, as 2**256 is at least as large
    // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
    // or ~bnTarget / (nTarget+1) + 1.
    return (~bnTarget / (bnTarget + 1)) + 1;
}
<commit_msg>I don't know wtf it is, but BOB's wormhole is yielding different results... for some unknown reason<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <math.h>
#include "pow.h"

#include "chain.h"
#include "chainparams.h"
#include "primitives/block.h"
#include "uint256.h"
#include "util.h"

unsigned int static KimotoGravityWell(const CBlockIndex* pindexLast, const CBlockHeader *pblock, uint64_t TargetBlocksSpacingSeconds, uint64_t PastBlocksMin, uint64_t PastBlocksMax) {
    /* current difficulty formula, megacoin - kimoto gravity well */
    const CBlockIndex  *BlockLastSolved             = pindexLast;
    const CBlockIndex  *BlockReading                = pindexLast;
    const CBlockHeader *BlockCreating               = pblock;
                        BlockCreating               = BlockCreating;
    uint64_t              PastBlocksMass              = 0;
    int64_t               PastRateActualSeconds       = 0;
    int64_t               PastRateTargetSeconds       = 0;
    int64_t               LatestBlockTime             = BlockLastSolved->GetBlockTime();
    double              PastRateAdjustmentRatio     = double(1);
    uint256             PastDifficultyAverage;
    uint256             PastDifficultyAveragePrev;
    double              EventHorizonDeviation;
    double              EventHorizonDeviationFast;
    double              EventHorizonDeviationSlow;
    const uint256 bnProofOfWorkLimit = Params().ProofOfWorkLimit();

    if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || (uint64_t)BlockLastSolved->nHeight < PastBlocksMin) { return bnProofOfWorkLimit.GetCompact(); }

    for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
        if (PastBlocksMax > 0 && i > PastBlocksMax) { break; }
        PastBlocksMass++;

        if (i == 1) { PastDifficultyAverage.SetCompact(BlockReading->nBits); }
        else        { PastDifficultyAverage = ((uint256().SetCompact(BlockReading->nBits) - PastDifficultyAveragePrev) / i) + PastDifficultyAveragePrev; }
        PastDifficultyAveragePrev = PastDifficultyAverage;

        if (LatestBlockTime < BlockReading->GetBlockTime()) { LatestBlockTime = BlockReading->GetBlockTime(); }
        PastRateActualSeconds           = LatestBlockTime - BlockReading->GetBlockTime();
        PastRateTargetSeconds           = TargetBlocksSpacingSeconds * PastBlocksMass;
        PastRateAdjustmentRatio         = double(1);
        if (PastRateActualSeconds < 1) { PastRateActualSeconds = 1; }
        if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) {
        PastRateAdjustmentRatio         = double(PastRateTargetSeconds) / double(PastRateActualSeconds);
        }
        EventHorizonDeviation           = 1 + (0.7084 * pow((double(PastBlocksMass)/double(9)), -1.228));
        EventHorizonDeviationFast       = EventHorizonDeviation;
        EventHorizonDeviationSlow       = 1 / EventHorizonDeviation;

        if (PastBlocksMass >= PastBlocksMin) {
            if ((PastRateAdjustmentRatio <= EventHorizonDeviationSlow) || (PastRateAdjustmentRatio >= EventHorizonDeviationFast)) { assert(BlockReading); break; }
        }
        if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
        BlockReading = BlockReading->pprev;
    }

    uint256 bnNew;
    bnNew=PastDifficultyAverage;
    if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) {
        bnNew *= PastRateActualSeconds;
        bnNew /= PastRateTargetSeconds;
    }
    if (bnNew > bnProofOfWorkLimit) { bnNew = bnProofOfWorkLimit; }

    /// debug print
    LogPrintf("Difficulty Retarget - BOB's Wormh0le (KGW)\n");
    LogPrintf("PastRateAdjustmentRatio = %g\n", PastRateAdjustmentRatio);
    LogPrintf("Before: %08x  %s\n", BlockLastSolved->nBits, uint256().SetCompact(BlockLastSolved->nBits).ToString().c_str());
    LogPrintf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString().c_str());

    return bnNew.GetCompact();
}

unsigned int static GetNextWorkRequired_V2(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    static const int64_t  BlocksTargetSpacing         = 10 * 60; // 10 minutes
    unsigned int        TimeDaySeconds              = 60 * 60 * 24;
    int64_t               PastSecondsMin              = TimeDaySeconds * 0.0625;
    int64_t               PastSecondsMax              = TimeDaySeconds * 1.75;
    uint64_t              PastBlocksMin               = PastSecondsMin / BlocksTargetSpacing;
    uint64_t              PastBlocksMax               = PastSecondsMax / BlocksTargetSpacing;

    return KimotoGravityWell(pindexLast, pblock, BlocksTargetSpacing, PastBlocksMin, PastBlocksMax);
}

unsigned int GetNextWorkRequired_V1(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();

    // Genesis block
    if (pindexLast == NULL)
        return nProofOfWorkLimit;

    // Only change once per interval
    if ((pindexLast->nHeight+1) % Params().Interval() != 0)
    {
        if (Params().AllowMinDifficultyBlocks())
        {
            // Special difficulty rule for testnet:
            // If the new block's timestamp is more than 2* 10 minutes
            // then allow mining of a min-difficulty block.
            if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + Params().TargetSpacing()*2)
                return nProofOfWorkLimit;
            else
            {
                // Return the last non-special-min-difficulty-rules-block
                const CBlockIndex* pindex = pindexLast;
                while (pindex->pprev && pindex->nHeight % Params().Interval() != 0 && pindex->nBits == nProofOfWorkLimit)
                    pindex = pindex->pprev;
                return pindex->nBits;
            }
        }
        return pindexLast->nBits;
    }

    // Go back by what we want to be 14 days worth of blocks
    const CBlockIndex* pindexFirst = pindexLast;
    for (int i = 0; pindexFirst && i < Params().Interval()-1; i++)
        pindexFirst = pindexFirst->pprev;
    assert(pindexFirst);

    // Limit adjustment step
    int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
    LogPrintf("  nActualTimespan = %d  before bounds\n", nActualTimespan);
    if (nActualTimespan < Params().TargetTimespan()/4)
        nActualTimespan = Params().TargetTimespan()/4;
    if (nActualTimespan > Params().TargetTimespan()*4)
        nActualTimespan = Params().TargetTimespan()*4;

    // Retarget
    uint256 bnNew;
    uint256 bnOld;
    bnNew.SetCompact(pindexLast->nBits);
    bnOld = bnNew;
    bnNew *= nActualTimespan;
    bnNew /= Params().TargetTimespan();

    if (bnNew > Params().ProofOfWorkLimit())
        bnNew = Params().ProofOfWorkLimit();

    /// debug print
    LogPrintf("GetNextWorkRequired RETARGET\n");
    LogPrintf("Params().TargetTimespan() = %d    nActualTimespan = %d\n", Params().TargetTimespan(), nActualTimespan);
    LogPrintf("Before: %08x  %s\n", pindexLast->nBits, bnOld.ToString());
    LogPrintf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString());

    return bnNew.GetCompact();
}

unsigned int GetNextWorkRequired_V3(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{

    static const int64_t nTargetTimespan_V3 = 10*60 ; // dobbscoin: every 10 minutes
    static const int64_t nTargetSpacing_V3 = 10*60; // dobbscoin: 10 minutes
    static const int64_t nInterval_V3 = nTargetTimespan_V3 / nTargetSpacing_V3;

    unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();

    int64_t retargetTimespan = nTargetTimespan_V3; //Params().TargetTimespan();
    int64_t retargetInterval = nInterval_V3; //Params().Interval();

    //retargetInterval = Params().TargetTimespan() / Params().TargetSpacing();
    //retargetTimespan = Params().TargetTimespan();

    // Genesis block
    if (pindexLast == NULL)
        return nProofOfWorkLimit;

    // Only change once per interval
    if ((pindexLast->nHeight+1) % retargetInterval != 0)
    {
        if (Params().AllowMinDifficultyBlocks())
        {
            // Special difficulty rule for testnet:
            // If the new block's timestamp is more than 2* nTargetSpacing minutes
            // then allow mining of a min-difficulty block.
            if (pblock->nTime > pindexLast->nTime + nTargetSpacing_V3 * 30) //Params().TargetSpacing()*30)
                return nProofOfWorkLimit;
            else
            {
                // Return the last non-special-min-difficulty-rules-block
                const CBlockIndex* pindex = pindexLast;
                while (pindex->pprev && pindex->nHeight % retargetInterval != 0 && pindex->nBits == nProofOfWorkLimit)
                    pindex = pindex->pprev;
                return pindex->nBits;
            }
        }
        return pindexLast->nBits;
    }

    // Fractalcoin: This fixes an issue where a 51% attack can change difficulty at will.
    // Go back the full period unless it's the first retarget after genesis. Code courtesy of Art Forz
    int blockstogoback = retargetInterval-1;
    if ((pindexLast->nHeight+1) != retargetInterval)
        blockstogoback = retargetInterval;

    // Go back by what we want to be 14 days worth of blocks
    const CBlockIndex* pindexFirst = pindexLast;
    for (int i = 0; pindexFirst && i < blockstogoback; i++)
        pindexFirst = pindexFirst->pprev;
    assert(pindexFirst);

    // Limit adjustment step
    int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
    LogPrintf("  nActualTimespan = %d  before bounds\n", nActualTimespan);

    //DigiShield implementation - thanks to RealSolid & WDC for this code
    // amplitude filter - thanks to daft27 for this code
    nActualTimespan = retargetTimespan + (nActualTimespan - retargetTimespan)/8;

    if (nActualTimespan < (retargetTimespan - (retargetTimespan/4)) ) nActualTimespan = (retargetTimespan - (retargetTimespan/4));
    if (nActualTimespan > (retargetTimespan + (retargetTimespan/2)) ) nActualTimespan = (retargetTimespan + (retargetTimespan/2));

    // Retarget
    uint256 bnNew;
    uint256 bnOld;
    bnNew.SetCompact(pindexLast->nBits);
    bnOld = bnNew;
    //scale up for millisecond granularity
    bnNew *= nActualTimespan;
    //slingshield effectively works by making the target block time longer temporarily
    bnNew /= (retargetTimespan);

    if (bnNew > Params().ProofOfWorkLimit())
        bnNew = Params().ProofOfWorkLimit();

    /// debug print
    LogPrintf("GetNextWorkRequired DIGISHIELD RETARGET\n");
    LogPrintf("Params().TargetTimespan() = %d    nActualTimespan = %d\n", Params().TargetTimespan(), nActualTimespan);
    LogPrintf("Before: %08x  %s\n", pindexLast->nBits, bnOld.ToString());
    LogPrintf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString());
    return bnNew.GetCompact();
}

unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    int DiffMode = 1;
    if (Params().AllowMinDifficultyBlocks()) {
        if (pindexLast->nHeight+1 >= 50) { DiffMode = 2; }
        if (pindexLast->nHeight+1 >= 100) { DiffMode = 3; }

    }
    else
    {
        if (pindexLast->nHeight+1 >= 13579) { DiffMode = 2; } // KGW @ Block 13579
        if(pindexLast->nHeight+1 >= 31597) { DiffMode = 3; } //switch to dobbshield @ block 31597
    }
    if      (DiffMode == 1) { return GetNextWorkRequired_V1(pindexLast, pblock); }
    else if (DiffMode == 2) { return GetNextWorkRequired_V2(pindexLast, pblock); }
    else if (DiffMode == 3) { return GetNextWorkRequired_V3(pindexLast, pblock); }
    return GetNextWorkRequired_V3(pindexLast, pblock); //never reached..
}

bool CheckProofOfWork(uint256 hash, unsigned int nBits)
{
    bool fNegative;
    bool fOverflow;
    uint256 bnTarget;

    if(hash==HASHGENESISBLOCKPOW) //ignore genesis block
    {
        return true;
    }

    if (Params().SkipProofOfWorkCheck())
       return true;

    bnTarget.SetCompact(nBits, &fNegative, &fOverflow);

    // Check range
    if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit())
        return error("CheckProofOfWork() : nBits below minimum work");

    // Check proof of work matches claimed amount
    if (hash > bnTarget)
        return error("CheckProofOfWork() : hash doesn't match nBits");

    return true;
}

uint256 GetBlockProof(const CBlockIndex& block)
{
    uint256 bnTarget;
    bool fNegative;
    bool fOverflow;
    bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
    if (fNegative || fOverflow || bnTarget == 0)
        return 0;
    // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
    // as it's too large for a uint256. However, as 2**256 is at least as large
    // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
    // or ~bnTarget / (nTarget+1) + 1.
    return (~bnTarget / (bnTarget + 1)) + 1;
}
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <functional>
#include <cmath>
#include <random>
#include <iostream>
#include <vector>
#include <utility>
#include "tbb/parallel_sort.h"
#include "tbb/mutex.h"
#include "tbb/pipeline.h"
#include "util.hpp"
#include "point.hpp"

#define VALUE(x) std::cout << #x "=" << x << std::endl

namespace psh
{
	template<uint d, class T>
	class map
	{
		static_assert(d > 0, "d must be larger than 0.");
	public:
		struct data_t
		{
			point<d> location;
			T contents;
		};

		struct bucket : public std::vector<data_t>
		{
			uint phi_index;

			bucket(uint phi_index) : phi_index(phi_index) { }
			friend bool operator<(const bucket& lhs, const bucket& rhs) {
				return lhs.size() > rhs.size();
			}
		};

		uint M0;
		uint M1;
		uint n;
		uint m_bar;
		uint m;
		uint r_bar;
		uint r;
		std::vector<point<d>> phi;
		std::vector<bool> H_b;
		std::vector<T> H;
		std::default_random_engine generator;

		map(const std::vector<data_t>& data)
			: n(data.size()), m_bar(std::ceil(std::pow(n, 1.0f / d))), m(std::pow(m_bar, d)),
			  r_bar(std::ceil(std::pow(n / d, 1.0f / d)) - 1), generator(time(0))
		{
			M0 = prime();
			while ((M1 = prime()) == M0);

			VALUE(m);
			VALUE(m_bar);

			bool create_succeeded = false;

			std::uniform_int_distribution<uint> m_dist(0, m - 1);

			do
			{
				r_bar += d;
				r = std::pow(r_bar, d);
				VALUE(r);
				VALUE(r_bar);

				create_succeeded = create(data, m_dist);

			} while (!create_succeeded);
		}

		uint prime()
		{
			static const std::vector<uint> primes{ 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289,
				24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469 };
			static std::uniform_int_distribution<uint> prime_dist(0, primes.size() - 1);

			return primes[prime_dist(generator)];
		}

		bool bad_m_r()
		{
			auto m_mod_r = m_bar % r_bar;
			return m_mod_r == 1 || m_mod_r == r - 1;
		}

		void insert(const bucket& b, decltype(H)& H_hat, decltype(H_b)& H_b_hat,
			const decltype(phi)& phi_hat)
		{
			for (auto& element : b)
			{
				auto hashed = h(element.location, phi_hat);
				auto i = point_to_index<d>(hashed, m_bar, m);
				H_hat[i] = element.contents;
				H_b_hat[i] = true;
			}
		}

		bool jiggle_offsets(decltype(H)& H_hat, decltype(H_b)& H_b_hat,
			decltype(phi)& phi_hat, const bucket& b,
			std::uniform_int_distribution<uint>& m_dist)
		{
			uint start_offset = m_dist(generator);

			bool found = false;
			point<d> found_offset;
			tbb::mutex mutex;

			uint chunk_index = 0;
			const uint num_cores = 8;
			const uint group_size = r / num_cores + 1;

			tbb::parallel_pipeline(num_cores,
				tbb::make_filter<void, uint>(tbb::filter::serial,
					[=, &chunk_index, &found, &group_size](tbb::flow_control& fc) {
						if (found || chunk_index >= r)
						{
							fc.stop();
						}
						chunk_index += group_size;
						return chunk_index;
					}) &
				tbb::make_filter<uint, void>(tbb::filter::parallel,
					[=, &mutex, &found, &found_offset, &b, &phi_hat, &H_hat, &H_b_hat](uint i0)
					{
						for (uint i = i0; i < i0 + group_size && !found; i++)
						{
							auto phi_offset = index_to_point<d>((start_offset + i) % m, m_bar, m);

							bool collision = false;
							for (auto& element : b)
							{
								auto h0 = M0 * element.location;
								auto h1 = M1 * element.location;
								auto index = point_to_index<d>(h1, r_bar, r);
								auto offset = index == b.phi_index ? phi_offset : phi_hat[index];
								auto hash = h0 + offset;

								collision = H_b_hat[point_to_index<d>(hash, m_bar, m)];
								if (collision)
									break;
							}

							if (!collision)
							{
								tbb::mutex::scoped_lock lock(mutex);
								if (!found)
								{
									found = true;
									found_offset = phi_offset;
								}
							}
						}
					})
				);
			if (found)
			{
				phi_hat[b.phi_index] = found_offset;
				insert(b, H_hat, H_b_hat, phi_hat);
				return true;
			}
			return false;
		}

		std::vector<bucket> create_buckets(const std::vector<data_t>& data)
		{
			std::vector<bucket> buckets;
			buckets.reserve(r);
			{
				uint i = 0;
				std::generate_n(std::back_inserter(buckets), r, [&] {
						return bucket(i++);
					});
			}

			for (auto& element : data)
			{
				auto h1 = M1 * element.location;
				buckets[point_to_index<d>(h1, r_bar, r)].push_back(element);
			}

			std::cout << "buckets created" << std::endl;

			tbb::parallel_sort(buckets.begin(), buckets.end());
			std::cout << "buckets sorted" << std::endl;

			return buckets;
		}

		bool create(const std::vector<data_t>& data, std::uniform_int_distribution<uint>& m_dist)
		{
			decltype(phi) phi_hat;
			phi_hat.reserve(r);
			decltype(H) H_hat;
			H_hat.reserve(m);
			decltype(H_b) H_b_hat(m, false);
			std::cout << "creating " << r << " buckets" << std::endl;

			if (bad_m_r())
				return false;

			auto buckets = create_buckets(data);
			std::cout << "jiggling offsets" << std::endl;

			for (uint i = 0; i < buckets.size(); i++)
			{
				if (buckets[i].size() == 0)
					break;
				if (i % (buckets.size() / 10) == 0)
					std::cout << (100 * i) / buckets.size() << "% done" << std::endl;

				if (!jiggle_offsets(H_hat, H_b_hat, phi_hat, buckets[i], m_dist))
				{
					return false;
				}
			}

			std::cout << "done!" << std::endl;
			phi = std::move(phi_hat);
			H = std::move(H_hat);
			H_b = std::move(H_b_hat);
			return true;
		}

		point<d> h(const point<d>& p, const decltype(phi)& phi_hat) const
		{
			auto h0 = M0 * p;
			auto h1 = M1 * p;
			auto offset = phi_hat[point_to_index<d>(h1, r_bar, r)];
			return h0 + offset;
		}

		point<d> h(const point<d>& p) const
		{
			return h(p, phi);
		}

		T get(const point<d>& p) const
		{
			auto i = point_to_index<d>(h(p), m_bar, m);
			if (H_b[i])
				return H[i];
			else
				throw std::out_of_range("Element not found in map");
		}

		uint memory_size() const
		{
			return sizeof(*this)
				+ sizeof(typename decltype(phi)::value_type) * phi.capacity()
				+ sizeof(typename decltype(H)::value_type) * H.capacity();
		}
	};
}<commit_msg>added another 'vector<bool>' to keep track of phi insertions<commit_after>#pragma once

#include <string>
#include <functional>
#include <cmath>
#include <random>
#include <iostream>
#include <vector>
#include <utility>
#include "tbb/parallel_sort.h"
#include "tbb/mutex.h"
#include "tbb/pipeline.h"
#include "util.hpp"
#include "point.hpp"

#define VALUE(x) std::cout << #x "=" << x << std::endl

namespace psh
{
	template<uint d, class T>
	class map
	{
		static_assert(d > 0, "d must be larger than 0.");
	public:
		struct data_t
		{
			point<d> location;
			T contents;
		};

		struct bucket : public std::vector<data_t>
		{
			uint phi_index;

			bucket(uint phi_index) : phi_index(phi_index) { }
			friend bool operator<(const bucket& lhs, const bucket& rhs) {
				return lhs.size() > rhs.size();
			}
		};

		uint M0;
		uint M1;
		uint n;
		uint m_bar;
		uint m;
		uint r_bar;
		uint r;
		std::vector<bool> phi_b;
		std::vector<point<d>> phi;
		std::vector<bool> H_b;
		std::vector<T> H;
		std::default_random_engine generator;

		map(const std::vector<data_t>& data)
			: n(data.size()), m_bar(std::ceil(std::pow(n, 1.0f / d))), m(std::pow(m_bar, d)),
			  r_bar(std::ceil(std::pow(n / d, 1.0f / d)) - 1), generator(time(0))
		{
			M0 = prime();
			while ((M1 = prime()) == M0);

			VALUE(m);
			VALUE(m_bar);

			bool create_succeeded = false;

			std::uniform_int_distribution<uint> m_dist(0, m - 1);

			do
			{
				r_bar += d;
				r = std::pow(r_bar, d);
				VALUE(r);
				VALUE(r_bar);

				create_succeeded = create(data, m_dist);

			} while (!create_succeeded);
		}

		uint prime()
		{
			static const std::vector<uint> primes{ 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289,
				24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469 };
			static std::uniform_int_distribution<uint> prime_dist(0, primes.size() - 1);

			return primes[prime_dist(generator)];
		}

		bool bad_m_r()
		{
			auto m_mod_r = m_bar % r_bar;
			return m_mod_r == 1 || m_mod_r == r - 1;
		}

		void insert(const bucket& b, decltype(H)& H_hat, decltype(H_b)& H_b_hat,
			const decltype(phi)& phi_hat, const decltype(phi_b)& phi_b_hat)
		{
			for (auto& element : b)
			{
				auto hashed = h(element.location, phi_hat, phi_b_hat);
				auto i = point_to_index<d>(hashed, m_bar, m);
				H_hat[i] = element.contents;
				H_b_hat[i] = true;
			}
		}

		bool jiggle_offsets(decltype(H)& H_hat, decltype(H_b)& H_b_hat,
			decltype(phi)& phi_hat, decltype(phi_b)& phi_b_hat, const bucket& b,
			std::uniform_int_distribution<uint>& m_dist)
		{
			uint start_offset = m_dist(generator);

			bool found = false;
			point<d> found_offset;
			tbb::mutex mutex;

			uint chunk_index = 0;
			const uint num_cores = 8;
			const uint group_size = r / num_cores + 1;

			tbb::parallel_pipeline(num_cores,
				tbb::make_filter<void, uint>(tbb::filter::serial,
					[=, &chunk_index, &found, &group_size](tbb::flow_control& fc) {
						if (found || chunk_index >= r)
						{
							fc.stop();
						}
						chunk_index += group_size;
						return chunk_index;
					}) &
				tbb::make_filter<uint, void>(tbb::filter::parallel,
					[=, &mutex, &found, &found_offset, &b, &phi_hat, &phi_b_hat, &H_hat, &H_b_hat](uint i0)
					{
						for (uint i = i0; i < i0 + group_size && !found; i++)
						{
							auto phi_offset = index_to_point<d>((start_offset + i) % m, m_bar, m);

							bool collision = false;
							for (auto& element : b)
							{
								auto h0 = M0 * element.location;
								auto h1 = M1 * element.location;
								auto index = point_to_index<d>(h1, r_bar, r);
								auto offset = index == b.phi_index ? phi_offset : phi_hat[index];
								auto hash = h0 + offset;

								collision = H_b_hat[point_to_index<d>(hash, m_bar, m)];
								if (collision)
									break;
							}

							if (!collision)
							{
								tbb::mutex::scoped_lock lock(mutex);
								if (!found)
								{
									found = true;
									found_offset = phi_offset;
								}
							}
						}
					})
				);
			if (found)
			{
				phi_b_hat[b.phi_index] = true;
				phi_hat[b.phi_index] = found_offset;
				insert(b, H_hat, H_b_hat, phi_hat, phi_b_hat);
				return true;
			}
			return false;
		}

		std::vector<bucket> create_buckets(const std::vector<data_t>& data)
		{
			std::vector<bucket> buckets;
			buckets.reserve(r);
			{
				uint i = 0;
				std::generate_n(std::back_inserter(buckets), r, [&] {
						return bucket(i++);
					});
			}

			for (auto& element : data)
			{
				auto h1 = M1 * element.location;
				buckets[point_to_index<d>(h1, r_bar, r)].push_back(element);
			}

			std::cout << "buckets created" << std::endl;

			tbb::parallel_sort(buckets.begin(), buckets.end());
			std::cout << "buckets sorted" << std::endl;

			return buckets;
		}

		bool create(const std::vector<data_t>& data, std::uniform_int_distribution<uint>& m_dist)
		{
			decltype(phi) phi_hat;
			phi_hat.reserve(r);
			decltype(phi_b) phi_b_hat(r, false);
			decltype(H) H_hat;
			H_hat.reserve(m);
			decltype(H_b) H_b_hat(m, false);
			std::cout << "creating " << r << " buckets" << std::endl;

			if (bad_m_r())
				return false;

			auto buckets = create_buckets(data);
			std::cout << "jiggling offsets" << std::endl;

			for (uint i = 0; i < buckets.size(); i++)
			{
				if (buckets[i].size() == 0)
					break;
				if (i % (buckets.size() / 10) == 0)
					std::cout << (100 * i) / buckets.size() << "% done" << std::endl;

				if (!jiggle_offsets(H_hat, H_b_hat, phi_hat, phi_b_hat, buckets[i], m_dist))
				{
					return false;
				}
			}

			std::cout << "done!" << std::endl;
			phi = std::move(phi_hat);
			phi_b = std::move(phi_b_hat);
			H = std::move(H_hat);
			H_b = std::move(H_b_hat);
			return true;
		}

		point<d> h(const point<d>& p, const decltype(phi)& phi_hat,
			const decltype(phi_b)& phi_b_hat) const
		{
			auto h0 = M0 * p;
			auto h1 = M1 * p;
			auto i = point_to_index<d>(h1, r_bar, r);
			if (!phi_b_hat[i])
				throw std::out_of_range("Element not found in map");
			auto offset = phi_hat[i];
			return h0 + offset;
		}

		point<d> h(const point<d>& p) const
		{
			return h(p, phi, phi_b);
		}

		T get(const point<d>& p) const
		{
			auto i = point_to_index<d>(h(p), m_bar, m);
			if (H_b[i])
				return H[i];
			else
				throw std::out_of_range("Element not found in map");
		}

		uint memory_size() const
		{
			return sizeof(*this)
				+ sizeof(typename decltype(phi)::value_type) * phi.capacity()
				+ sizeof(typename decltype(phi_b)::value_type) * phi_b.capacity()
				+ sizeof(typename decltype(H)::value_type) * H.capacity()
				+ sizeof(typename decltype(H_b)::value_type) * H_b.capacity();
		}
	};
}<|endoftext|>


<commit_before>#include <bitcoin/blockchain/blockchain.hpp>

#include <bitcoin/utility/assert.hpp>

namespace libbitcoin {

using std::placeholders::_1;
using std::placeholders::_2;

typedef blockchain_fetch_handler_block handler_block;

class fetch_block_t
  : public std::enable_shared_from_this<fetch_block_t>
{
public:
    fetch_block_t(blockchain_ptr chain)
      : chain_(chain), stopped_(false) {}

    template <typename BlockIndex>
    void start(const BlockIndex& index, handler_block handle)
    {
        handle_ = handle;
        auto this_ptr = shared_from_this();
        chain_->fetch_block_header(index,
            [this, this_ptr](const std::error_code& ec,
                const message::block& block_header)
            {
                if (stop_on_error(ec))
                    return;
                block_ = block_header;
                fetch_hashes();
            });
    }

private:
    bool stop_on_error(const std::error_code& ec)
    {
        if (stopped_)
            return true;
        else if (ec)
        {
            stopped_ = true;
            handle_(ec, message::block());
            return true;
        }
        return false;
    }

    void fetch_hashes()
    {
        chain_->fetch_block_transaction_hashes(
            hash_block_header(block_),
            std::bind(&fetch_block_t::fetch_transactions,
                shared_from_this(), _1, _2));
    }

    void fetch_transactions(const std::error_code& ec,
        const message::inventory_list& tx_hashes)
    {
        if (stop_on_error(ec))
            return;
        block_.transactions.resize(tx_hashes.size());
        count_ = 0;
        for (size_t tx_index = 0;
            tx_index < tx_hashes.size(); ++tx_index)
        {
            fetch_tx(tx_hashes, tx_index);
        }
    }

    void fetch_tx(const message::inventory_list& tx_hashes, size_t tx_index)
    {
        auto this_ptr = shared_from_this();
        const message::inventory_vector& inv = tx_hashes[tx_index];
        BITCOIN_ASSERT(inv.type ==
            message::inventory_type::transaction);
        size_t tx_hashes_size = tx_hashes.size();
        chain_->fetch_transaction(inv.hash,
            [this, this_ptr, tx_index, tx_hashes_size](
                const std::error_code& ec,
                const message::transaction& tx)
            {
                if (stop_on_error(ec))
                    return;
                BITCOIN_ASSERT(tx_index < block_.transactions.size());
                block_.transactions[tx_index] = tx;
                ++count_;
                BITCOIN_ASSERT(block_.transactions.size() == tx_hashes_size);
                if (count_ == tx_hashes_size)
                    handle_(std::error_code(), block_);
            });
    }

    blockchain_ptr chain_;
    handler_block handle_;

    message::block block_;
    size_t count_;
    bool stopped_;
};

void fetch_block(blockchain_ptr chain, size_t depth,
    handler_block handle_fetch)
{
    auto fetcher = std::make_shared<fetch_block_t>(chain);
    fetcher->start(depth, handle_fetch);
}
void fetch_block(blockchain_ptr chain, const hash_digest& block_hash,
    handler_block handle_fetch)
{
    auto fetcher = std::make_shared<fetch_block_t>(chain);
    fetcher->start(block_hash, handle_fetch);
}

// fetch_block_locator
typedef blockchain_fetch_handler_block_locator handler_locator;

class fetch_locator
  : public std::enable_shared_from_this<fetch_locator>
{
public:
    fetch_locator(blockchain_ptr chain)
      : chain_(chain) {}

    void start(handler_locator handle)
    {
        handle_ = handle;
        auto this_ptr = shared_from_this();
        chain_->fetch_last_depth(
            std::bind(&fetch_locator::populate,
                this_ptr, _1, _2));
    }

private:
    // An intermediate type used to keep metadata about the locator
    // so we can sort the locator before returning.
    typedef std::pair<size_t, hash_digest> meta_entry;
    typedef std::vector<meta_entry> meta_locator;

    bool stop_on_error(const std::error_code& ec)
    {
        if (stopped_)
            return true;
        else if (ec)
        {
            stopped_ = true;
            handle_(ec, message::block_locator());
            return true;
        }
        return false;
    }

    void populate(const std::error_code& ec, size_t last_depth)
    {
        if (stop_on_error(ec))
            return;
        index_list indexes = block_locator_indexes(last_depth);
        auto this_ptr = shared_from_this();
        for (size_t depth: indexes)
            chain_->fetch_block_header(depth,
                std::bind(&fetch_locator::append,
                    this_ptr, _1, _2, depth, indexes.size()));
    }

    void append(const std::error_code& ec,
        const message::block& block_header, size_t depth, size_t entries)
    {
        if (stop_on_error(ec))
            return;
        meta_.push_back(std::make_pair(depth, hash_block_header(block_header)));
        if (meta_.size() == entries)
            final();
    }

    void final()
    {
        std::sort(meta_.begin(), meta_.end(),
            [](const meta_entry& entry_a, const meta_entry& entry_b)
            {
                return entry_a.first < entry_b.first;
            });
        message::block_locator final_locator;
        for (const meta_entry& entry: meta_)
            final_locator.push_back(entry.second);
        handle_(std::error_code(), final_locator);
    }

    blockchain_ptr chain_;
    handler_locator handle_;
    bool stopped_;
    meta_locator meta_;
};

void fetch_block_locator(blockchain_ptr chain, handler_locator handle_fetch)
{
    auto fetcher = std::make_shared<fetch_locator>(chain);
    fetcher->start(handle_fetch);
}

} // namespace libbitcoin

<commit_msg>Bugfix: fetch_block_locator returning entries reversed.<commit_after>#include <bitcoin/blockchain/blockchain.hpp>

#include <bitcoin/utility/assert.hpp>

namespace libbitcoin {

using std::placeholders::_1;
using std::placeholders::_2;

typedef blockchain_fetch_handler_block handler_block;

class fetch_block_t
  : public std::enable_shared_from_this<fetch_block_t>
{
public:
    fetch_block_t(blockchain_ptr chain)
      : chain_(chain), stopped_(false) {}

    template <typename BlockIndex>
    void start(const BlockIndex& index, handler_block handle)
    {
        handle_ = handle;
        auto this_ptr = shared_from_this();
        chain_->fetch_block_header(index,
            [this, this_ptr](const std::error_code& ec,
                const message::block& block_header)
            {
                if (stop_on_error(ec))
                    return;
                block_ = block_header;
                fetch_hashes();
            });
    }

private:
    bool stop_on_error(const std::error_code& ec)
    {
        if (stopped_)
            return true;
        else if (ec)
        {
            stopped_ = true;
            handle_(ec, message::block());
            return true;
        }
        return false;
    }

    void fetch_hashes()
    {
        chain_->fetch_block_transaction_hashes(
            hash_block_header(block_),
            std::bind(&fetch_block_t::fetch_transactions,
                shared_from_this(), _1, _2));
    }

    void fetch_transactions(const std::error_code& ec,
        const message::inventory_list& tx_hashes)
    {
        if (stop_on_error(ec))
            return;
        block_.transactions.resize(tx_hashes.size());
        count_ = 0;
        for (size_t tx_index = 0;
            tx_index < tx_hashes.size(); ++tx_index)
        {
            fetch_tx(tx_hashes, tx_index);
        }
    }

    void fetch_tx(const message::inventory_list& tx_hashes, size_t tx_index)
    {
        auto this_ptr = shared_from_this();
        const message::inventory_vector& inv = tx_hashes[tx_index];
        BITCOIN_ASSERT(inv.type ==
            message::inventory_type::transaction);
        size_t tx_hashes_size = tx_hashes.size();
        chain_->fetch_transaction(inv.hash,
            [this, this_ptr, tx_index, tx_hashes_size](
                const std::error_code& ec,
                const message::transaction& tx)
            {
                if (stop_on_error(ec))
                    return;
                BITCOIN_ASSERT(tx_index < block_.transactions.size());
                block_.transactions[tx_index] = tx;
                ++count_;
                BITCOIN_ASSERT(block_.transactions.size() == tx_hashes_size);
                if (count_ == tx_hashes_size)
                    handle_(std::error_code(), block_);
            });
    }

    blockchain_ptr chain_;
    handler_block handle_;

    message::block block_;
    size_t count_;
    bool stopped_;
};

void fetch_block(blockchain_ptr chain, size_t depth,
    handler_block handle_fetch)
{
    auto fetcher = std::make_shared<fetch_block_t>(chain);
    fetcher->start(depth, handle_fetch);
}
void fetch_block(blockchain_ptr chain, const hash_digest& block_hash,
    handler_block handle_fetch)
{
    auto fetcher = std::make_shared<fetch_block_t>(chain);
    fetcher->start(block_hash, handle_fetch);
}

// fetch_block_locator
typedef blockchain_fetch_handler_block_locator handler_locator;

class fetch_locator
  : public std::enable_shared_from_this<fetch_locator>
{
public:
    fetch_locator(blockchain_ptr chain)
      : chain_(chain) {}

    void start(handler_locator handle)
    {
        handle_ = handle;
        auto this_ptr = shared_from_this();
        chain_->fetch_last_depth(
            std::bind(&fetch_locator::populate,
                this_ptr, _1, _2));
    }

private:
    // An intermediate type used to keep metadata about the locator
    // so we can sort the locator before returning.
    typedef std::pair<size_t, hash_digest> meta_entry;
    typedef std::vector<meta_entry> meta_locator;

    bool stop_on_error(const std::error_code& ec)
    {
        if (stopped_)
            return true;
        else if (ec)
        {
            stopped_ = true;
            handle_(ec, message::block_locator());
            return true;
        }
        return false;
    }

    void populate(const std::error_code& ec, size_t last_depth)
    {
        if (stop_on_error(ec))
            return;
        index_list indexes = block_locator_indexes(last_depth);
        auto this_ptr = shared_from_this();
        for (size_t depth: indexes)
            chain_->fetch_block_header(depth,
                std::bind(&fetch_locator::append,
                    this_ptr, _1, _2, depth, indexes.size()));
    }

    void append(const std::error_code& ec,
        const message::block& block_header, size_t depth, size_t entries)
    {
        if (stop_on_error(ec))
            return;
        meta_.push_back(std::make_pair(depth, hash_block_header(block_header)));
        if (meta_.size() == entries)
            final();
    }

    void final()
    {
        std::sort(meta_.begin(), meta_.end(),
            [](const meta_entry& entry_a, const meta_entry& entry_b)
            {
                return entry_a.first > entry_b.first;
            });
        message::block_locator final_locator;
        for (const meta_entry& entry: meta_)
            final_locator.push_back(entry.second);
        handle_(std::error_code(), final_locator);
    }

    blockchain_ptr chain_;
    handler_locator handle_;
    bool stopped_;
    meta_locator meta_;
};

void fetch_block_locator(blockchain_ptr chain, handler_locator handle_fetch)
{
    auto fetcher = std::make_shared<fetch_locator>(chain);
    fetcher->start(handle_fetch);
}

} // namespace libbitcoin

<|endoftext|>


<commit_before>
// Visomics includes
#include "voDelimitedTextImportWidget.h"
#include "ui_voDelimitedTextImportWidget.h"
#include "voDelimitedTextPreviewModel.h"

class voDelimitedTextImportWidgetPrivate : public Ui_voDelimitedTextImportWidget
{
public:
  voDelimitedTextImportWidgetPrivate();

  void initWidgetFromModel();

  QButtonGroup DelimiterButtonGroup;

  voDelimitedTextPreviewModel * DelimitedTextPreviewModel;
};

// --------------------------------------------------------------------------
// voDelimitedTextImportWidgetPrivate methods

// --------------------------------------------------------------------------
voDelimitedTextImportWidgetPrivate::voDelimitedTextImportWidgetPrivate()
{
  this->DelimitedTextPreviewModel = 0;
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidgetPrivate::initWidgetFromModel()
{
  this->OtherLineEdit->setText(QString(":"));
  switch (this->DelimitedTextPreviewModel->fieldDelimiterCharacters().at(0).toLatin1())
    {
    case ',':
      this->CommaRadioButton->setChecked(true);
      break;
    case ';':
      this->SemicolonRadioButton->setChecked(true);
      break;
    case '\t':
      this->TabRadioButton->setChecked(true);
      break;
    case ' ':
      this->SpaceRadioButton->setChecked(true);
      break;
    default:
      this->OtherRadioButton->setChecked(true);
      this->OtherLineEdit->setText(this->DelimitedTextPreviewModel->fieldDelimiterCharacters());
      break;
    }

  this->StringDelimiterCheckBox->setChecked(this->DelimitedTextPreviewModel->useStringDelimiter());
  this->StringDelimiterLineEdit->setText(QString(QChar(this->DelimitedTextPreviewModel->stringDelimiter())));

  this->TransposeCheckBox->setChecked(this->DelimitedTextPreviewModel->transpose());

  this->NumberHeaderColumnsSpinBox->setValue(this->DelimitedTextPreviewModel->numberOfRowMetaDataTypes());

  if(this->DelimitedTextPreviewModel->numberOfRowMetaDataTypes() > 0)
    {
    this->HeaderColumnOfInterestSpinBox->setRange(0, this->DelimitedTextPreviewModel->numberOfRowMetaDataTypes()-1);
    this->HeaderColumnOfInterestSpinBox->setValue(this->DelimitedTextPreviewModel->rowMetaDataTypeOfInterest());
    this->HeaderColumnOfInterestSpinBox->setEnabled(true);
    }
  else
    {
    this->HeaderColumnOfInterestSpinBox->setMinimum(-1);
    this->HeaderColumnOfInterestSpinBox->setValue(-1);
    this->HeaderColumnOfInterestSpinBox->setEnabled(false);
    }

  this->NumberHeaderRowsSpinBox->setValue(this->DelimitedTextPreviewModel->numberOfColumnMetaDataTypes());

  if(this->DelimitedTextPreviewModel->numberOfColumnMetaDataTypes() > 0)
    {
    this->HeaderRowOfInterestSpinBox->setRange(0, this->DelimitedTextPreviewModel->numberOfColumnMetaDataTypes()-1);
    this->HeaderRowOfInterestSpinBox->setValue(this->DelimitedTextPreviewModel->columnMetaDataTypeOfInterest());
    this->HeaderRowOfInterestSpinBox->setEnabled(true);
    }
  else
    {
    this->HeaderRowOfInterestSpinBox->setMinimum(-1);
    this->HeaderRowOfInterestSpinBox->setValue(-1);
    this->HeaderRowOfInterestSpinBox->setEnabled(false);
    }
}

// --------------------------------------------------------------------------
// voDelimitedTextImportWidget methods

// --------------------------------------------------------------------------
voDelimitedTextImportWidget::voDelimitedTextImportWidget(QWidget* newParent) :
  Superclass(newParent), d_ptr(new voDelimitedTextImportWidgetPrivate())
{
  Q_D(voDelimitedTextImportWidget);
  d->setupUi(this);

  d->DelimiterButtonGroup.addButton(d->CommaRadioButton, ',');
  d->DelimiterButtonGroup.addButton(d->SemicolonRadioButton, ';');
  d->DelimiterButtonGroup.addButton(d->TabRadioButton, '\t');
  d->DelimiterButtonGroup.addButton(d->SpaceRadioButton, ' ');
  d->DelimiterButtonGroup.addButton(d->OtherRadioButton, 'x');

  // Delimiter connections
  connect(&d->DelimiterButtonGroup, SIGNAL(buttonClicked(int)),
          this, SLOT(onDelimiterChanged(int)));

  // StringBeginEndCharacter connection
  connect(d->StringDelimiterCheckBox, SIGNAL(toggled(bool)),
          this, SLOT(onStringDelimiterEnabled(bool)));
}

// --------------------------------------------------------------------------
voDelimitedTextImportWidget::~voDelimitedTextImportWidget()
{
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::insertWidget(QWidget * widget, InsertWidgetLocation location)
{
  Q_D(voDelimitedTextImportWidget);
  if (!widget)
    {
    return;
    }
  int index = -1;
  if (location == Self::DelimiterGroupBox)
    {
    index = d->MainVerticalLayout->indexOf(d->DelimiterGroupBox);
    }
  else if (location == Self::RowsAndColumnsGroupBox)
    {
    index = d->MainVerticalLayout->indexOf(d->RowsColumnsGroupBox);
    }
  Q_ASSERT(index != -1);
  d->MainVerticalLayout->insertWidget(index, widget);
}

// --------------------------------------------------------------------------
voDelimitedTextPreviewModel* voDelimitedTextImportWidget::delimitedTextPreviewModel()
{
  Q_D(voDelimitedTextImportWidget);
  return d->DelimitedTextPreviewModel;
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::setDelimitedTextPreviewModel(voDelimitedTextPreviewModel* model)
{
  Q_D(voDelimitedTextImportWidget);
  if (d->DelimitedTextPreviewModel == model)
    {
    return;
    }

  // Disconnect model
  if (d->DelimitedTextPreviewModel)
    {
    // Widget -> Model connections
    disconnect(d->TransposeCheckBox, SIGNAL(toggled(bool)),
              d->DelimitedTextPreviewModel, SLOT(setTranspose(bool)));

    disconnect(d->NumberHeaderColumnsSpinBox, SIGNAL(valueChanged(int)),
              d->DelimitedTextPreviewModel, SLOT(setNumberOfRowMetaDataTypes(int)));

    disconnect(d->HeaderColumnOfInterestSpinBox, SIGNAL(valueChanged(int)),
              d->DelimitedTextPreviewModel, SLOT(setRowMetaDataTypeOfInterest(int)));

    disconnect(d->NumberHeaderRowsSpinBox, SIGNAL(valueChanged(int)),
              d->DelimitedTextPreviewModel, SLOT(setNumberOfColumnMetaDataTypes(int)));

    disconnect(d->HeaderRowOfInterestSpinBox, SIGNAL(valueChanged(int)),
              d->DelimitedTextPreviewModel, SLOT(setColumnMetaDataTypeOfInterest(int)));

    // Model -> Widget connections
    disconnect(d->DelimitedTextPreviewModel, SIGNAL(numberOfColumnMetaDataTypesChanged(int)),
              this, SLOT(onNumberOfColumnMetaDataTypesChanged(int)));
    disconnect(d->DelimitedTextPreviewModel, SIGNAL(columnMetaDataTypeOfInterestChanged(int)),
              this, SLOT(onColumnMetaDataTypeOfInterestChanged(int)));

    disconnect(d->DelimitedTextPreviewModel, SIGNAL(numberOfRowMetaDataTypesChanged(int)),
              this, SLOT(onNumberOfRowMetaDataTypesChanged(int)));
    disconnect(d->DelimitedTextPreviewModel, SIGNAL(rowMetaDataTypeOfInterestChanged(int)),
              this, SLOT(onRowMetaDataTypeOfInterestChanged(int)));
    }

  d->DelimitedTextPreviewModel = model;

  if (d->DelimitedTextPreviewModel)
    {
    d->initWidgetFromModel();

    // Widget -> Model connections
    connect(d->TransposeCheckBox, SIGNAL(toggled(bool)),
            d->DelimitedTextPreviewModel, SLOT(setTranspose(bool)));

    connect(d->NumberHeaderColumnsSpinBox, SIGNAL(valueChanged(int)),
            d->DelimitedTextPreviewModel, SLOT(setNumberOfRowMetaDataTypes(int)));

    connect(d->HeaderColumnOfInterestSpinBox, SIGNAL(valueChanged(int)),
            d->DelimitedTextPreviewModel, SLOT(setRowMetaDataTypeOfInterest(int)));

    connect(d->NumberHeaderRowsSpinBox, SIGNAL(valueChanged(int)),
            d->DelimitedTextPreviewModel, SLOT(setNumberOfColumnMetaDataTypes(int)));

    connect(d->HeaderRowOfInterestSpinBox, SIGNAL(valueChanged(int)),
            d->DelimitedTextPreviewModel, SLOT(setColumnMetaDataTypeOfInterest(int)));

    // Model -> Widget connections
    connect(d->DelimitedTextPreviewModel, SIGNAL(numberOfColumnMetaDataTypesChanged(int)),
            this, SLOT(onNumberOfColumnMetaDataTypesChanged(int)));
    connect(d->DelimitedTextPreviewModel, SIGNAL(columnMetaDataTypeOfInterestChanged(int)),
            this, SLOT(onColumnMetaDataTypeOfInterestChanged(int)));

    connect(d->DelimitedTextPreviewModel, SIGNAL(numberOfRowMetaDataTypesChanged(int)),
            this, SLOT(onNumberOfRowMetaDataTypesChanged(int)));
    connect(d->DelimitedTextPreviewModel, SIGNAL(rowMetaDataTypeOfInterestChanged(int)),
            this, SLOT(onRowMetaDataTypeOfInterestChanged(int)));
    }
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onNumberOfColumnMetaDataTypesChanged(int value)
{
  Q_D(voDelimitedTextImportWidget);
  d->NumberHeaderRowsSpinBox->setValue(value);

  if(value > 0)
    {
    d->HeaderRowOfInterestSpinBox->setRange(0, value-1);
    }
  else
    {
    d->HeaderRowOfInterestSpinBox->setMinimum(-1);
    }
  d->HeaderRowOfInterestSpinBox->setEnabled(value > 0);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onColumnMetaDataTypeOfInterestChanged(int value)
{
  Q_D(voDelimitedTextImportWidget);
  d->HeaderRowOfInterestSpinBox->setValue(value);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onNumberOfRowMetaDataTypesChanged(int value)
{
  Q_D(voDelimitedTextImportWidget);
  d->NumberHeaderColumnsSpinBox->setValue(value);

  if(value > 0)
    {
    d->HeaderColumnOfInterestSpinBox->setRange(0, value-1);
    }
  else
    {
    d->HeaderColumnOfInterestSpinBox->setMinimum(-1);
    }
  d->HeaderColumnOfInterestSpinBox->setEnabled(value > 0);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onRowMetaDataTypeOfInterestChanged(int value)
{
  Q_D(voDelimitedTextImportWidget);
  d->HeaderColumnOfInterestSpinBox->setValue(value);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onDelimiterChanged(int delimiter)
{
  Q_D(voDelimitedTextImportWidget);
  if (delimiter == 'x')
    { // Special case triggered by OtherRadioButton
    QString text = d->OtherLineEdit->text();

    connect(d->OtherLineEdit, SIGNAL(textChanged(const QString&)),
            this, SLOT(onOtherDelimiterLineEditChanged(const QString&)));

    if (text.isEmpty())
      {
      return;
      }
    delimiter = text.at(0).toLatin1();
    }
  else
    {
    disconnect(d->OtherLineEdit, SIGNAL(textChanged(const QString&)),
               this, SLOT(onOtherDelimiterLineEditChanged(const QString&)));
    }
  d->DelimitedTextPreviewModel->setFieldDelimiter(delimiter);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onOtherDelimiterLineEditChanged(const QString& text)
{
  Q_D(voDelimitedTextImportWidget);
  if (text.isEmpty())
    {
    return;
    }
  char delimiter = d->OtherLineEdit->text().at(0).toLatin1();
  d->DelimitedTextPreviewModel->setFieldDelimiter(delimiter);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onStringDelimiterEnabled(bool value)
{
  Q_D(voDelimitedTextImportWidget);
  char character = 0;
  if (value)
    {
    QString text = d->StringDelimiterLineEdit->text();

    connect(d->StringDelimiterLineEdit, SIGNAL(textChanged(const QString&)),
            this, SLOT(onStringDelimiterLineEditChanged(const QString&)));

    if (text.isEmpty())
      {
      return;
      }
    character = text.at(0).toLatin1();
    }
  else
    {
    disconnect(d->StringDelimiterLineEdit, SIGNAL(textChanged(const QString&)),
               this, SLOT(onStringDelimiterLineEditChanged(const QString&)));
    }
  d->DelimitedTextPreviewModel->setStringDelimiter(character);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onStringDelimiterLineEditChanged(const QString& text)
{
  Q_D(voDelimitedTextImportWidget);
  if (text.isEmpty())
    {
    return;
    }
  char character = d->StringDelimiterLineEdit->text().at(0).toLatin1();
  d->DelimitedTextPreviewModel->setStringDelimiter(character);
}
<commit_msg>Fix voDelimitedTextImportWidget::insertWidget function<commit_after>
// Visomics includes
#include "voDelimitedTextImportWidget.h"
#include "ui_voDelimitedTextImportWidget.h"
#include "voDelimitedTextPreviewModel.h"

class voDelimitedTextImportWidgetPrivate : public Ui_voDelimitedTextImportWidget
{
public:
  voDelimitedTextImportWidgetPrivate();

  void initWidgetFromModel();

  QButtonGroup DelimiterButtonGroup;

  voDelimitedTextPreviewModel * DelimitedTextPreviewModel;
};

// --------------------------------------------------------------------------
// voDelimitedTextImportWidgetPrivate methods

// --------------------------------------------------------------------------
voDelimitedTextImportWidgetPrivate::voDelimitedTextImportWidgetPrivate()
{
  this->DelimitedTextPreviewModel = 0;
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidgetPrivate::initWidgetFromModel()
{
  this->OtherLineEdit->setText(QString(":"));
  switch (this->DelimitedTextPreviewModel->fieldDelimiterCharacters().at(0).toLatin1())
    {
    case ',':
      this->CommaRadioButton->setChecked(true);
      break;
    case ';':
      this->SemicolonRadioButton->setChecked(true);
      break;
    case '\t':
      this->TabRadioButton->setChecked(true);
      break;
    case ' ':
      this->SpaceRadioButton->setChecked(true);
      break;
    default:
      this->OtherRadioButton->setChecked(true);
      this->OtherLineEdit->setText(this->DelimitedTextPreviewModel->fieldDelimiterCharacters());
      break;
    }

  this->StringDelimiterCheckBox->setChecked(this->DelimitedTextPreviewModel->useStringDelimiter());
  this->StringDelimiterLineEdit->setText(QString(QChar(this->DelimitedTextPreviewModel->stringDelimiter())));

  this->TransposeCheckBox->setChecked(this->DelimitedTextPreviewModel->transpose());

  this->NumberHeaderColumnsSpinBox->setValue(this->DelimitedTextPreviewModel->numberOfRowMetaDataTypes());

  if(this->DelimitedTextPreviewModel->numberOfRowMetaDataTypes() > 0)
    {
    this->HeaderColumnOfInterestSpinBox->setRange(0, this->DelimitedTextPreviewModel->numberOfRowMetaDataTypes()-1);
    this->HeaderColumnOfInterestSpinBox->setValue(this->DelimitedTextPreviewModel->rowMetaDataTypeOfInterest());
    this->HeaderColumnOfInterestSpinBox->setEnabled(true);
    }
  else
    {
    this->HeaderColumnOfInterestSpinBox->setMinimum(-1);
    this->HeaderColumnOfInterestSpinBox->setValue(-1);
    this->HeaderColumnOfInterestSpinBox->setEnabled(false);
    }

  this->NumberHeaderRowsSpinBox->setValue(this->DelimitedTextPreviewModel->numberOfColumnMetaDataTypes());

  if(this->DelimitedTextPreviewModel->numberOfColumnMetaDataTypes() > 0)
    {
    this->HeaderRowOfInterestSpinBox->setRange(0, this->DelimitedTextPreviewModel->numberOfColumnMetaDataTypes()-1);
    this->HeaderRowOfInterestSpinBox->setValue(this->DelimitedTextPreviewModel->columnMetaDataTypeOfInterest());
    this->HeaderRowOfInterestSpinBox->setEnabled(true);
    }
  else
    {
    this->HeaderRowOfInterestSpinBox->setMinimum(-1);
    this->HeaderRowOfInterestSpinBox->setValue(-1);
    this->HeaderRowOfInterestSpinBox->setEnabled(false);
    }
}

// --------------------------------------------------------------------------
// voDelimitedTextImportWidget methods

// --------------------------------------------------------------------------
voDelimitedTextImportWidget::voDelimitedTextImportWidget(QWidget* newParent) :
  Superclass(newParent), d_ptr(new voDelimitedTextImportWidgetPrivate())
{
  Q_D(voDelimitedTextImportWidget);
  d->setupUi(this);

  d->DelimiterButtonGroup.addButton(d->CommaRadioButton, ',');
  d->DelimiterButtonGroup.addButton(d->SemicolonRadioButton, ';');
  d->DelimiterButtonGroup.addButton(d->TabRadioButton, '\t');
  d->DelimiterButtonGroup.addButton(d->SpaceRadioButton, ' ');
  d->DelimiterButtonGroup.addButton(d->OtherRadioButton, 'x');

  // Delimiter connections
  connect(&d->DelimiterButtonGroup, SIGNAL(buttonClicked(int)),
          this, SLOT(onDelimiterChanged(int)));

  // StringBeginEndCharacter connection
  connect(d->StringDelimiterCheckBox, SIGNAL(toggled(bool)),
          this, SLOT(onStringDelimiterEnabled(bool)));
}

// --------------------------------------------------------------------------
voDelimitedTextImportWidget::~voDelimitedTextImportWidget()
{
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::insertWidget(QWidget * widget, InsertWidgetLocation location)
{
  Q_D(voDelimitedTextImportWidget);
  if (!widget)
    {
    return;
    }
  int index = -1;
  if (location == Self::DelimiterGroupBox)
    {
    index = d->MainVerticalLayout->indexOf(d->DelimiterGroupBox);
    }
  else if (location == Self::RowsAndColumnsGroupBox)
    {
    index = d->MainVerticalLayout->indexOf(d->RowsColumnsGroupBox);
    }
  Q_ASSERT(index != -1);
  d->MainVerticalLayout->insertWidget(index + 1, widget);
}

// --------------------------------------------------------------------------
voDelimitedTextPreviewModel* voDelimitedTextImportWidget::delimitedTextPreviewModel()
{
  Q_D(voDelimitedTextImportWidget);
  return d->DelimitedTextPreviewModel;
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::setDelimitedTextPreviewModel(voDelimitedTextPreviewModel* model)
{
  Q_D(voDelimitedTextImportWidget);
  if (d->DelimitedTextPreviewModel == model)
    {
    return;
    }

  // Disconnect model
  if (d->DelimitedTextPreviewModel)
    {
    // Widget -> Model connections
    disconnect(d->TransposeCheckBox, SIGNAL(toggled(bool)),
              d->DelimitedTextPreviewModel, SLOT(setTranspose(bool)));

    disconnect(d->NumberHeaderColumnsSpinBox, SIGNAL(valueChanged(int)),
              d->DelimitedTextPreviewModel, SLOT(setNumberOfRowMetaDataTypes(int)));

    disconnect(d->HeaderColumnOfInterestSpinBox, SIGNAL(valueChanged(int)),
              d->DelimitedTextPreviewModel, SLOT(setRowMetaDataTypeOfInterest(int)));

    disconnect(d->NumberHeaderRowsSpinBox, SIGNAL(valueChanged(int)),
              d->DelimitedTextPreviewModel, SLOT(setNumberOfColumnMetaDataTypes(int)));

    disconnect(d->HeaderRowOfInterestSpinBox, SIGNAL(valueChanged(int)),
              d->DelimitedTextPreviewModel, SLOT(setColumnMetaDataTypeOfInterest(int)));

    // Model -> Widget connections
    disconnect(d->DelimitedTextPreviewModel, SIGNAL(numberOfColumnMetaDataTypesChanged(int)),
              this, SLOT(onNumberOfColumnMetaDataTypesChanged(int)));
    disconnect(d->DelimitedTextPreviewModel, SIGNAL(columnMetaDataTypeOfInterestChanged(int)),
              this, SLOT(onColumnMetaDataTypeOfInterestChanged(int)));

    disconnect(d->DelimitedTextPreviewModel, SIGNAL(numberOfRowMetaDataTypesChanged(int)),
              this, SLOT(onNumberOfRowMetaDataTypesChanged(int)));
    disconnect(d->DelimitedTextPreviewModel, SIGNAL(rowMetaDataTypeOfInterestChanged(int)),
              this, SLOT(onRowMetaDataTypeOfInterestChanged(int)));
    }

  d->DelimitedTextPreviewModel = model;

  if (d->DelimitedTextPreviewModel)
    {
    d->initWidgetFromModel();

    // Widget -> Model connections
    connect(d->TransposeCheckBox, SIGNAL(toggled(bool)),
            d->DelimitedTextPreviewModel, SLOT(setTranspose(bool)));

    connect(d->NumberHeaderColumnsSpinBox, SIGNAL(valueChanged(int)),
            d->DelimitedTextPreviewModel, SLOT(setNumberOfRowMetaDataTypes(int)));

    connect(d->HeaderColumnOfInterestSpinBox, SIGNAL(valueChanged(int)),
            d->DelimitedTextPreviewModel, SLOT(setRowMetaDataTypeOfInterest(int)));

    connect(d->NumberHeaderRowsSpinBox, SIGNAL(valueChanged(int)),
            d->DelimitedTextPreviewModel, SLOT(setNumberOfColumnMetaDataTypes(int)));

    connect(d->HeaderRowOfInterestSpinBox, SIGNAL(valueChanged(int)),
            d->DelimitedTextPreviewModel, SLOT(setColumnMetaDataTypeOfInterest(int)));

    // Model -> Widget connections
    connect(d->DelimitedTextPreviewModel, SIGNAL(numberOfColumnMetaDataTypesChanged(int)),
            this, SLOT(onNumberOfColumnMetaDataTypesChanged(int)));
    connect(d->DelimitedTextPreviewModel, SIGNAL(columnMetaDataTypeOfInterestChanged(int)),
            this, SLOT(onColumnMetaDataTypeOfInterestChanged(int)));

    connect(d->DelimitedTextPreviewModel, SIGNAL(numberOfRowMetaDataTypesChanged(int)),
            this, SLOT(onNumberOfRowMetaDataTypesChanged(int)));
    connect(d->DelimitedTextPreviewModel, SIGNAL(rowMetaDataTypeOfInterestChanged(int)),
            this, SLOT(onRowMetaDataTypeOfInterestChanged(int)));
    }
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onNumberOfColumnMetaDataTypesChanged(int value)
{
  Q_D(voDelimitedTextImportWidget);
  d->NumberHeaderRowsSpinBox->setValue(value);

  if(value > 0)
    {
    d->HeaderRowOfInterestSpinBox->setRange(0, value-1);
    }
  else
    {
    d->HeaderRowOfInterestSpinBox->setMinimum(-1);
    }
  d->HeaderRowOfInterestSpinBox->setEnabled(value > 0);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onColumnMetaDataTypeOfInterestChanged(int value)
{
  Q_D(voDelimitedTextImportWidget);
  d->HeaderRowOfInterestSpinBox->setValue(value);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onNumberOfRowMetaDataTypesChanged(int value)
{
  Q_D(voDelimitedTextImportWidget);
  d->NumberHeaderColumnsSpinBox->setValue(value);

  if(value > 0)
    {
    d->HeaderColumnOfInterestSpinBox->setRange(0, value-1);
    }
  else
    {
    d->HeaderColumnOfInterestSpinBox->setMinimum(-1);
    }
  d->HeaderColumnOfInterestSpinBox->setEnabled(value > 0);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onRowMetaDataTypeOfInterestChanged(int value)
{
  Q_D(voDelimitedTextImportWidget);
  d->HeaderColumnOfInterestSpinBox->setValue(value);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onDelimiterChanged(int delimiter)
{
  Q_D(voDelimitedTextImportWidget);
  if (delimiter == 'x')
    { // Special case triggered by OtherRadioButton
    QString text = d->OtherLineEdit->text();

    connect(d->OtherLineEdit, SIGNAL(textChanged(const QString&)),
            this, SLOT(onOtherDelimiterLineEditChanged(const QString&)));

    if (text.isEmpty())
      {
      return;
      }
    delimiter = text.at(0).toLatin1();
    }
  else
    {
    disconnect(d->OtherLineEdit, SIGNAL(textChanged(const QString&)),
               this, SLOT(onOtherDelimiterLineEditChanged(const QString&)));
    }
  d->DelimitedTextPreviewModel->setFieldDelimiter(delimiter);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onOtherDelimiterLineEditChanged(const QString& text)
{
  Q_D(voDelimitedTextImportWidget);
  if (text.isEmpty())
    {
    return;
    }
  char delimiter = d->OtherLineEdit->text().at(0).toLatin1();
  d->DelimitedTextPreviewModel->setFieldDelimiter(delimiter);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onStringDelimiterEnabled(bool value)
{
  Q_D(voDelimitedTextImportWidget);
  char character = 0;
  if (value)
    {
    QString text = d->StringDelimiterLineEdit->text();

    connect(d->StringDelimiterLineEdit, SIGNAL(textChanged(const QString&)),
            this, SLOT(onStringDelimiterLineEditChanged(const QString&)));

    if (text.isEmpty())
      {
      return;
      }
    character = text.at(0).toLatin1();
    }
  else
    {
    disconnect(d->StringDelimiterLineEdit, SIGNAL(textChanged(const QString&)),
               this, SLOT(onStringDelimiterLineEditChanged(const QString&)));
    }
  d->DelimitedTextPreviewModel->setStringDelimiter(character);
}

// --------------------------------------------------------------------------
void voDelimitedTextImportWidget::onStringDelimiterLineEditChanged(const QString& text)
{
  Q_D(voDelimitedTextImportWidget);
  if (text.isEmpty())
    {
    return;
    }
  char character = d->StringDelimiterLineEdit->text().at(0).toLatin1();
  d->DelimitedTextPreviewModel->setStringDelimiter(character);
}
<|endoftext|>