<commit_before>// Copyright 2009, Squish Tech, LLC.

#include <v8.h>

#include <libxml/xmlmemory.h>

#include "libxmljs.h"
#include "xml_document.h"
#include "xml_node.h"
#include "xml_sax_parser.h"

namespace libxmljs {

bool tlsInitialized = false;
nauv_key_t tlsKey;
bool isAsync = false; // Only set on V8 thread when no workers are running
int numWorkers = 0; // Only access from V8 thread

// Set up in V8 thread
WorkerParent::WorkerParent() : memAdjustments(0) {
    if (!tlsInitialized)
    {
        nauv_key_create(&tlsKey);
        tlsInitialized = true;
    }
    if (numWorkers++ == 0)
    {
        isAsync = true;
    }
}

// Tear down in V8 thread
WorkerParent::~WorkerParent() {
    NanAdjustExternalMemory(memAdjustments);
    if (--numWorkers == 0)
    {
        isAsync = false;
    }
}

// Set up in worker thread
WorkerSentinel::WorkerSentinel(WorkerParent& parent) : parent(parent) {
    nauv_key_set(&tlsKey, this);
}

// Tear down in worker thread
WorkerSentinel::~WorkerSentinel() {
    nauv_key_set(&tlsKey, NULL);
}

struct memHdr {
    size_t size;
};

// When we move to C++11 one day, the following would become constexpr,
// and SLIGN_SIZE could perhaps become sizeof(std::max_align_t).
#define ALIGN_SIZE sizeof(double)
#define HDR_SIZE (((sizeof(memHdr) + (ALIGN_SIZE - 1))/ALIGN_SIZE)*ALIGN_SIZE)

inline void* hdr2client(memHdr* hdr) {
    return static_cast<void*>(reinterpret_cast<char*>(hdr) + HDR_SIZE);
}

inline memHdr* client2hdr(void* client) {
    return reinterpret_cast<memHdr*>(static_cast<char*>(client) - HDR_SIZE);
}

void adjustMem(ssize_t diff)
{
    if (isAsync)
    {
        WorkerSentinel* worker =
            static_cast<WorkerSentinel*>(nauv_key_get(&tlsKey));
        if (worker)
        {
            worker->parent.memAdjustments += diff;
            return;
        }
    }
    // if v8 is no longer running, don't try to adjust memory
    // this happens when the v8 vm is shutdown and the program is exiting
    // our cleanup routines for libxml will be called (freeing memory)
    // but v8 is already offline and does not need to be informed
    // trying to adjust after shutdown will result in a fatal error
#if (NODE_MODULE_VERSION > 0x000B)
    if (v8::Isolate::GetCurrent() == 0)
    {
        assert(diff <= 0);
        return;
    }
#endif
    if (v8::V8::IsDead())
    {
        assert(diff <= 0);
        return;
    }
    NanAdjustExternalMemory(diff);
}

void* memMalloc(size_t size)
{
    size_t totalSize = size + HDR_SIZE;
    memHdr* mem = static_cast<memHdr*>(malloc(totalSize));
    if (!mem) return NULL;
    mem->size = size;
    adjustMem(totalSize);
    return hdr2client(mem);
}

void memFree(void* p)
{
    memHdr* mem = client2hdr(p);
    ssize_t totalSize = mem->size + HDR_SIZE;
    adjustMem(-totalSize);
    free(mem);
}

void* memRealloc(void* ptr, size_t size)
{
    memHdr* mem1 = client2hdr(ptr);
    ssize_t oldSize = mem1->size;
    memHdr* mem2 = static_cast<memHdr*>(realloc(mem1, size + HDR_SIZE));
    if (!mem2) return NULL;
    mem2->size = size;
    adjustMem(ssize_t(size) - oldSize);
    return hdr2client(mem2);
}

char* memStrdup(const char* str)
{
    size_t size = strlen(str) + 1;
    char* res = static_cast<char*>(memMalloc(size));
    if (res) memcpy(res, str, size);
    return res;
}

// ensure destruction at exit time
// v8 doesn't cleanup its resources
LibXMLJS LibXMLJS::instance;

LibXMLJS::LibXMLJS()
{
    // Setup our own memory handling (see xmlmemory.h/c)
    xmlMemSetup(memFree, memMalloc, memRealloc, memStrdup);

    // initialize libxml
    LIBXML_TEST_VERSION;
}

LibXMLJS::~LibXMLJS()
{
    xmlCleanupParser();
}

v8::Local<v8::Object> listFeatures() {
    v8::Local<v8::Object> target = NanNew<v8::Object>();
#define FEAT(x) target->Set(NanNew<v8::String>(# x), \
                    NanNew<v8::Boolean>(xmlHasFeature(XML_WITH_ ## x)))
    // See enum xmlFeature in parser.h
    FEAT(THREAD);
    FEAT(TREE);
    FEAT(OUTPUT);
    FEAT(PUSH);
    FEAT(READER);
    FEAT(PATTERN);
    FEAT(WRITER);
    FEAT(SAX1);
    FEAT(FTP);
    FEAT(HTTP);
    FEAT(VALID);
    FEAT(HTML);
    FEAT(LEGACY);
    FEAT(C14N);
    FEAT(CATALOG);
    FEAT(XPATH);
    FEAT(XPTR);
    FEAT(XINCLUDE);
    FEAT(ICONV);
    FEAT(ISO8859X);
    FEAT(UNICODE);
    FEAT(REGEXP);
    FEAT(AUTOMATA);
    FEAT(EXPR);
    FEAT(SCHEMAS);
    FEAT(SCHEMATRON);
    FEAT(MODULES);
    FEAT(DEBUG);
    FEAT(DEBUG_MEM);
    FEAT(DEBUG_RUN);
    FEAT(ZLIB);
    FEAT(ICU);
    FEAT(LZMA);
    return target;
}

// used by node.js to initialize libraries
extern "C" void
init(v8::Handle<v8::Object> target)
{
      NanScope();

      XmlDocument::Initialize(target);
      XmlSaxParser::Initialize(target);

      target->Set(NanNew<v8::String>("libxml_version"),
                  NanNew<v8::String>(LIBXML_DOTTED_VERSION));

      target->Set(NanNew<v8::String>("libxml_parser_version"),
                  NanNew<v8::String>(xmlParserVersion));

      target->Set(NanNew<v8::String>("libxml_debug_enabled"),
                  NanNew<v8::Boolean>(debugging));

      target->Set(NanNew<v8::String>("features"), listFeatures());

      target->Set(NanNew<v8::String>("libxml"), target);
}

NODE_MODULE(xmljs, init)

}  // namespace libxmljs
<commit_msg>Make use of offsetof to compute header size<commit_after>// Copyright 2009, Squish Tech, LLC.

#include <v8.h>

#include <libxml/xmlmemory.h>

#include "libxmljs.h"
#include "xml_document.h"
#include "xml_node.h"
#include "xml_sax_parser.h"

namespace libxmljs {

bool tlsInitialized = false;
nauv_key_t tlsKey;
bool isAsync = false; // Only set on V8 thread when no workers are running
int numWorkers = 0; // Only access from V8 thread

// Set up in V8 thread
WorkerParent::WorkerParent() : memAdjustments(0) {
    if (!tlsInitialized)
    {
        nauv_key_create(&tlsKey);
        tlsInitialized = true;
    }
    if (numWorkers++ == 0)
    {
        isAsync = true;
    }
}

// Tear down in V8 thread
WorkerParent::~WorkerParent() {
    NanAdjustExternalMemory(memAdjustments);
    if (--numWorkers == 0)
    {
        isAsync = false;
    }
}

// Set up in worker thread
WorkerSentinel::WorkerSentinel(WorkerParent& parent) : parent(parent) {
    nauv_key_set(&tlsKey, this);
}

// Tear down in worker thread
WorkerSentinel::~WorkerSentinel() {
    nauv_key_set(&tlsKey, NULL);
}

struct memHdr {
    size_t size;
    double data;
};

#define HDR_SIZE offsetof(memHdr, data)

inline void* hdr2client(memHdr* hdr) {
    return static_cast<void*>(reinterpret_cast<char*>(hdr) + HDR_SIZE);
}

inline memHdr* client2hdr(void* client) {
    return reinterpret_cast<memHdr*>(static_cast<char*>(client) - HDR_SIZE);
}

void adjustMem(ssize_t diff)
{
    if (isAsync)
    {
        WorkerSentinel* worker =
            static_cast<WorkerSentinel*>(nauv_key_get(&tlsKey));
        if (worker)
        {
            worker->parent.memAdjustments += diff;
            return;
        }
    }
    // if v8 is no longer running, don't try to adjust memory
    // this happens when the v8 vm is shutdown and the program is exiting
    // our cleanup routines for libxml will be called (freeing memory)
    // but v8 is already offline and does not need to be informed
    // trying to adjust after shutdown will result in a fatal error
#if (NODE_MODULE_VERSION > 0x000B)
    if (v8::Isolate::GetCurrent() == 0)
    {
        assert(diff <= 0);
        return;
    }
#endif
    if (v8::V8::IsDead())
    {
        assert(diff <= 0);
        return;
    }
    NanAdjustExternalMemory(diff);
}

void* memMalloc(size_t size)
{
    size_t totalSize = size + HDR_SIZE;
    memHdr* mem = static_cast<memHdr*>(malloc(totalSize));
    if (!mem) return NULL;
    mem->size = size;
    adjustMem(totalSize);
    return hdr2client(mem);
}

void memFree(void* p)
{
    memHdr* mem = client2hdr(p);
    ssize_t totalSize = mem->size + HDR_SIZE;
    adjustMem(-totalSize);
    free(mem);
}

void* memRealloc(void* ptr, size_t size)
{
    memHdr* mem1 = client2hdr(ptr);
    ssize_t oldSize = mem1->size;
    memHdr* mem2 = static_cast<memHdr*>(realloc(mem1, size + HDR_SIZE));
    if (!mem2) return NULL;
    mem2->size = size;
    adjustMem(ssize_t(size) - oldSize);
    return hdr2client(mem2);
}

char* memStrdup(const char* str)
{
    size_t size = strlen(str) + 1;
    char* res = static_cast<char*>(memMalloc(size));
    if (res) memcpy(res, str, size);
    return res;
}

// ensure destruction at exit time
// v8 doesn't cleanup its resources
LibXMLJS LibXMLJS::instance;

LibXMLJS::LibXMLJS()
{
    // Setup our own memory handling (see xmlmemory.h/c)
    xmlMemSetup(memFree, memMalloc, memRealloc, memStrdup);

    // initialize libxml
    LIBXML_TEST_VERSION;
}

LibXMLJS::~LibXMLJS()
{
    xmlCleanupParser();
}

v8::Local<v8::Object> listFeatures() {
    v8::Local<v8::Object> target = NanNew<v8::Object>();
#define FEAT(x) target->Set(NanNew<v8::String>(# x), \
                    NanNew<v8::Boolean>(xmlHasFeature(XML_WITH_ ## x)))
    // See enum xmlFeature in parser.h
    FEAT(THREAD);
    FEAT(TREE);
    FEAT(OUTPUT);
    FEAT(PUSH);
    FEAT(READER);
    FEAT(PATTERN);
    FEAT(WRITER);
    FEAT(SAX1);
    FEAT(FTP);
    FEAT(HTTP);
    FEAT(VALID);
    FEAT(HTML);
    FEAT(LEGACY);
    FEAT(C14N);
    FEAT(CATALOG);
    FEAT(XPATH);
    FEAT(XPTR);
    FEAT(XINCLUDE);
    FEAT(ICONV);
    FEAT(ISO8859X);
    FEAT(UNICODE);
    FEAT(REGEXP);
    FEAT(AUTOMATA);
    FEAT(EXPR);
    FEAT(SCHEMAS);
    FEAT(SCHEMATRON);
    FEAT(MODULES);
    FEAT(DEBUG);
    FEAT(DEBUG_MEM);
    FEAT(DEBUG_RUN);
    FEAT(ZLIB);
    FEAT(ICU);
    FEAT(LZMA);
    return target;
}

// used by node.js to initialize libraries
extern "C" void
init(v8::Handle<v8::Object> target)
{
      NanScope();

      XmlDocument::Initialize(target);
      XmlSaxParser::Initialize(target);

      target->Set(NanNew<v8::String>("libxml_version"),
                  NanNew<v8::String>(LIBXML_DOTTED_VERSION));

      target->Set(NanNew<v8::String>("libxml_parser_version"),
                  NanNew<v8::String>(xmlParserVersion));

      target->Set(NanNew<v8::String>("libxml_debug_enabled"),
                  NanNew<v8::Boolean>(debugging));

      target->Set(NanNew<v8::String>("features"), listFeatures());

      target->Set(NanNew<v8::String>("libxml"), target);
}

NODE_MODULE(xmljs, init)

}  // namespace libxmljs
<|endoftext|>


<commit_before>/*
This file is part of khmer, https://github.com/dib-lab/khmer/, and is
Copyright (C) 2016, The Regents of the University of California.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

    * Neither the name of the University of California nor the names
      of its contributors may be used to endorse or promote products
      derived from this software without specific prior written
      permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
LICENSE (END)

Contact: khmer-project@idyll.org
*/

#ifndef BITSTORAGE_HH
#define BITSTORAGE_HH

namespace khmer
{
typedef std::map<HashIntoType, BoundedCounterType> KmerCountMap;
class Hashbits;
class CountingHash;

//
// base Storage class for hashtable-related storage of information in memory.
//

class Storage {
public:
    bool _use_bigcount;

    Storage() : _use_bigcount(false) { } ;
    virtual ~Storage() { }
    virtual std::vector<uint64_t> get_tablesizes() const = 0;
    virtual const size_t n_tables() const = 0;
    virtual void save(std::string, WordLength) = 0;
    virtual void load(std::string, WordLength&) = 0;
    virtual const uint64_t n_occupied() const = 0;
    virtual const uint64_t n_unique_kmers() const = 0;
    virtual BoundedCounterType test_and_set_bits( HashIntoType khash ) = 0;
    virtual void add(HashIntoType khash) = 0;
    virtual const BoundedCounterType get_count(HashIntoType khash) const = 0;
    virtual Byte ** get_raw_tables() = 0;

    void set_use_bigcount(bool b);
    bool get_use_bigcount();
};

//
// BitStorage: a Bloom filter implementation.
//

class BitStorage : public Storage
{
friend class Hashbits;
protected:
    std::vector<uint64_t> _tablesizes;
    size_t _n_tables;
    uint64_t _occupied_bins;
    uint64_t _n_unique_kmers;
    Byte ** _counts;

    BitStorage(std::vector<uint64_t>& tablesizes) :
        _tablesizes(tablesizes)
    {
        _occupied_bins = 0;
        _n_unique_kmers = 0;

        _allocate_counters();
    }
    ~BitStorage() {
        if (_counts) {
            for (size_t i = 0; i < _n_tables; i++) {
                delete[] _counts[i];
                _counts[i] = NULL;
            }
            delete[] _counts;
            _counts = NULL;

            _n_tables = 0;
        }
    }

    void _allocate_counters()
    {
        _n_tables = _tablesizes.size();

        _counts = new Byte*[_n_tables];

        for (size_t i = 0; i < _n_tables; i++) {
            uint64_t tablesize = _tablesizes[i];
            uint64_t tablebytes = tablesize / 8 + 1;

            _counts[i] = new Byte[tablebytes];
            memset(_counts[i], 0, tablebytes);
        }
    }

    // Accessors for protected/private table info members
    std::vector<uint64_t> get_tablesizes() const
    {
        return _tablesizes;
    }

    const size_t n_tables() const
    {
        return _n_tables;
    }

    void save(std::string, WordLength ksize);
    void load(std::string, WordLength& ksize);

    // count number of occupied bins
    const uint64_t n_occupied() const
    {
        return _occupied_bins;
    }

    const uint64_t n_unique_kmers() const
    {
        return _n_unique_kmers;
    }

    // Get and set the hashbits for the given kmer hash.
    // Generally, it is better to keep tests and mutations separate,
    // but, in the interests of efficiency and thread safety,
    // tests and mutations are being blended here against conventional
    // software engineering wisdom.
    inline
    BoundedCounterType
    test_and_set_bits( HashIntoType khash )
    {
        bool is_new_kmer = false;

        for (size_t i = 0; i < _n_tables; i++) {
            uint64_t bin = khash % _tablesizes[i];
            uint64_t byte = bin / 8;
            unsigned char bit = (unsigned char)(1 << (bin % 8));

            unsigned char bits_orig = __sync_fetch_and_or( *(_counts + i) +
                                      byte, bit );
            if (!(bits_orig & bit)) {
                if (i == 0) {
                    __sync_add_and_fetch( &_occupied_bins, 1 );
                }
                is_new_kmer = true;
            }
        } // iteration over hashtables

        if (is_new_kmer) {
            __sync_add_and_fetch( &_n_unique_kmers, 1 );
            return 1; // kmer not seen before
        }

        return 0; // kmer already seen
    } // test_and_set_bits

    inline void add(HashIntoType khash)
    {
        test_and_set_bits(khash);
    }

    // get the count for the given k-mer hash.
    inline const BoundedCounterType get_count(HashIntoType khash) const
    {
        for (size_t i = 0; i < _n_tables; i++) {
            uint64_t bin = khash % _tablesizes[i];
            uint64_t byte = bin / 8;
            unsigned char bit = bin % 8;

            if (!(_counts[i][byte] & (1 << bit))) {
                return 0;
            }
        }
        return 1;
    }

    // Writing to the tables outside of defined methods has undefined behavior!
    // As such, this should only be used to return read-only interfaces
    Byte ** get_raw_tables()
    {
        return _counts;
    }

    void update_from(const BitStorage&);
};

//
// ByteStorage: a CountMin sketch implementation.
//

class CountingHashFile;
class CountingHashFileReader;
class CountingHashFileWriter;
class CountingHashGzFileReader;
class CountingHashGzFileWriter;

class ByteStorage : public Storage {
    friend class CountingHashFile;
    friend class CountingHashFileReader;
    friend class CountingHashFileWriter;
    friend class CountingHashGzFileReader;
    friend class CountingHashGzFileWriter;
    friend class CountingHash;
protected:
    unsigned int    _max_count;
    unsigned int    _max_bigcount;

    uint32_t _bigcount_spin_lock;
    std::vector<uint64_t> _tablesizes;
    size_t _n_tables;
    uint64_t _n_unique_kmers;
    uint64_t _occupied_bins;

    Byte ** _counts;

    // initialize counts with empty hashtables.
    void _allocate_counters()
    {
        _n_tables = _tablesizes.size();

        _counts = new Byte*[_n_tables];
        for (size_t i = 0; i < _n_tables; i++) {
            _counts[i] = new Byte[_tablesizes[i]];
            memset(_counts[i], 0, _tablesizes[i]);
        }
    }
public:
    KmerCountMap _bigcounts;

    // constructor: create an empty CountMin sketch.
    ByteStorage(std::vector<uint64_t>& tablesizes ) :
        _max_count(MAX_KCOUNT), _max_bigcount(MAX_BIGCOUNT),
        _bigcount_spin_lock(false), _tablesizes(tablesizes),
        _n_unique_kmers(0), _occupied_bins(0)
    {

        _allocate_counters();
    }

    // destructor: clear out the memory.
    ~ByteStorage()
    {
        if (_counts) {
            for (size_t i = 0; i < _n_tables; i++) {
                if (_counts[i]) {
                    delete[] _counts[i];
                    _counts[i] = NULL;
                }
            }

            delete[] _counts;
            _counts = NULL;

            _n_tables = 0;
        }
    }

    std::vector<uint64_t> get_tablesizes() const { return _tablesizes; }

    const uint64_t n_unique_kmers() const { return _n_unique_kmers; }
    const size_t n_tables() const { return _n_tables; }
    const uint64_t n_occupied() const { return _occupied_bins; }

    void save(std::string, WordLength);
    void load(std::string, WordLength&);

    inline BoundedCounterType test_and_set_bits(HashIntoType khash)
    {
        BoundedCounterType x = get_count(khash);
        add(khash);
        return !x;
    }

    inline void add(HashIntoType khash)
    {
        bool is_new_kmer = false;
        unsigned int  n_full	  = 0;

        // add one to each entry in each table.
        for (unsigned int i = 0; i < _n_tables; i++) {
            const uint64_t bin = khash % _tablesizes[i];
            Byte current_count = _counts[ i ][ bin ];
            if (!is_new_kmer) {
                if (current_count == 0) {
                    is_new_kmer = true;

                    // track occupied bins in the first table only, as proxy
                    // for all.
                    if (i == 0) {
                        __sync_add_and_fetch(&_occupied_bins, 1);
                    }
                }
            }
            // NOTE: Technically, multiple threads can cause the bin to spill
            //	 over max_count a little, if they all read it as less than
            //	 max_count before any of them increment it.
            //	 However, do we actually care if there is a little
            //	 bit of slop here? It can always be trimmed off later, if
            //	 that would help with stats.

            if ( _max_count > current_count ) {
                __sync_add_and_fetch( *(_counts + i) + bin, 1 );
            } else {
                n_full++;
            }
        } // for each table

        // if all tables are full for this position, then add in bigcounts.
        if (n_full == _n_tables && _use_bigcount) {
            while (!__sync_bool_compare_and_swap(&_bigcount_spin_lock, 0, 1));
            if (_bigcounts[khash] == 0) {
                _bigcounts[khash] = _max_count + 1;
            } else {
                if (_bigcounts[khash] < _max_bigcount) {
                    _bigcounts[khash] += 1;
                }
            }
            __sync_bool_compare_and_swap( &_bigcount_spin_lock, 1, 0 );
        }

        if (is_new_kmer) {
            __sync_add_and_fetch(&_n_unique_kmers, 1);
        }

    }

    // get the count for the given k-mer hash.
    inline const BoundedCounterType get_count(HashIntoType khash) const
    {
        unsigned int	  max_count	= _max_count;
        BoundedCounterType  min_count	= max_count; // bound count by max.

        // first, get the min count across all tables (standard CMS).
        for (unsigned int i = 0; i < _n_tables; i++) {
            BoundedCounterType the_count = _counts[i][khash % _tablesizes[i]];
            if (the_count < min_count) {
                min_count = the_count;
            }
        }

        // if the count is saturated, check in the bigcount structure to
        // see if we've accumulated more counts.
        if (min_count == max_count && _use_bigcount) {
            KmerCountMap::const_iterator it = _bigcounts.find(khash);
            if (it != _bigcounts.end()) {
                min_count = it->second;
            }
        }
        return min_count;
    }
    // Get direct access to the counts.
    //
    // Note:
    // Writing to the tables outside of defined methods has undefined behavior!
    // As such, this should only be used to return read-only interfaces
    Byte ** get_raw_tables()
    {
        return _counts;
    }

};

class CountingHashFile
{
public:
    static void load(const std::string &infilename,
                     WordLength &ksize,
                     ByteStorage &store);
    static void save(const std::string &outfilename,
                     const WordLength ksize,
                     const ByteStorage &store);
};

class CountingHashFileReader : public CountingHashFile
{
public:
    CountingHashFileReader(const std::string &infilename,
                           WordLength &ksize,
                           ByteStorage &store);
};

class CountingHashGzFileReader : public CountingHashFile
{
public:
    CountingHashGzFileReader(const std::string &infilename,
                             WordLength &ksize,
                             ByteStorage &store);
};

class CountingHashFileWriter : public CountingHashFile
{
public:
    CountingHashFileWriter(const std::string &outfilename,
                           const WordLength ksize,
                           const ByteStorage &store);
};

class CountingHashGzFileWriter : public CountingHashFile
{
public:
    CountingHashGzFileWriter(const std::string &outfilename,
                             const WordLength ksize,
                             const ByteStorage &store);
};
}

#endif // BITSTORAGE_HH
<commit_msg>some more cleanup<commit_after>/*
This file is part of khmer, https://github.com/dib-lab/khmer/, and is
Copyright (C) 2016, The Regents of the University of California.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

    * Neither the name of the University of California nor the names
      of its contributors may be used to endorse or promote products
      derived from this software without specific prior written
      permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
LICENSE (END)

Contact: khmer-project@idyll.org
*/

#ifndef STORAGE_HH
#define STORAGE_HH

namespace khmer
{
typedef std::map<HashIntoType, BoundedCounterType> KmerCountMap;
class Hashbits;
class CountingHash;

//
// base Storage class for hashtable-related storage of information in memory.
//

class Storage {
public:
    bool _use_bigcount;

    Storage() : _use_bigcount(false) { } ;
    virtual ~Storage() { }
    virtual std::vector<uint64_t> get_tablesizes() const = 0;
    virtual const size_t n_tables() const = 0;
    virtual void save(std::string, WordLength) = 0;
    virtual void load(std::string, WordLength&) = 0;
    virtual const uint64_t n_occupied() const = 0;
    virtual const uint64_t n_unique_kmers() const = 0;
    virtual BoundedCounterType test_and_set_bits( HashIntoType khash ) = 0;
    virtual void add(HashIntoType khash) = 0;
    virtual const BoundedCounterType get_count(HashIntoType khash) const = 0;
    virtual Byte ** get_raw_tables() = 0;

    void set_use_bigcount(bool b);
    bool get_use_bigcount();
};

/*
 * \class BitStorage
 *
 * \brief A Bloom filter implementation.
 *
 * BitStorage is used to track presence/absence of k-mers by Hashtable
 * and derived classes.  It contains 'n_tables' different tables of
 * bitsizes specified in 'tablesizes' (so 1/8 for bytesizes).
 *
 * Like other Storage classes, BitStorage manages setting the bits and
 * tracking statistics, as well as save/load, and not much else.
 *
 */

class BitStorage : public Storage
{
friend class Hashbits;
protected:
    std::vector<uint64_t> _tablesizes;
    size_t _n_tables;
    uint64_t _occupied_bins;
    uint64_t _n_unique_kmers;
    Byte ** _counts;

    BitStorage(std::vector<uint64_t>& tablesizes) :
        _tablesizes(tablesizes)
    {
        _occupied_bins = 0;
        _n_unique_kmers = 0;

        _allocate_counters();
    }
    ~BitStorage() {
        if (_counts) {
            for (size_t i = 0; i < _n_tables; i++) {
                delete[] _counts[i];
                _counts[i] = NULL;
            }
            delete[] _counts;
            _counts = NULL;

            _n_tables = 0;
        }
    }

    void _allocate_counters()
    {
        _n_tables = _tablesizes.size();

        _counts = new Byte*[_n_tables];

        for (size_t i = 0; i < _n_tables; i++) {
            uint64_t tablesize = _tablesizes[i];
            uint64_t tablebytes = tablesize / 8 + 1;

            _counts[i] = new Byte[tablebytes];
            memset(_counts[i], 0, tablebytes);
        }
    }

    // Accessors for protected/private table info members
    std::vector<uint64_t> get_tablesizes() const
    {
        return _tablesizes;
    }

    const size_t n_tables() const
    {
        return _n_tables;
    }

    void save(std::string, WordLength ksize);
    void load(std::string, WordLength& ksize);

    // count number of occupied bins
    const uint64_t n_occupied() const
    {
        return _occupied_bins;
    }

    const uint64_t n_unique_kmers() const
    {
        return _n_unique_kmers;
    }

    // Get and set the hashbits for the given kmer hash.
    // Generally, it is better to keep tests and mutations separate,
    // but, in the interests of efficiency and thread safety,
    // tests and mutations are being blended here against conventional
    // software engineering wisdom.
    inline
    BoundedCounterType
    test_and_set_bits( HashIntoType khash )
    {
        bool is_new_kmer = false;

        for (size_t i = 0; i < _n_tables; i++) {
            uint64_t bin = khash % _tablesizes[i];
            uint64_t byte = bin / 8;
            unsigned char bit = (unsigned char)(1 << (bin % 8));

            unsigned char bits_orig = __sync_fetch_and_or( *(_counts + i) +
                                      byte, bit );
            if (!(bits_orig & bit)) {
                if (i == 0) {
                    __sync_add_and_fetch( &_occupied_bins, 1 );
                }
                is_new_kmer = true;
            }
        } // iteration over hashtables

        if (is_new_kmer) {
            __sync_add_and_fetch( &_n_unique_kmers, 1 );
            return 1; // kmer not seen before
        }

        return 0; // kmer already seen
    } // test_and_set_bits

    inline void add(HashIntoType khash)
    {
        test_and_set_bits(khash);
    }

    // get the count for the given k-mer hash.
    inline const BoundedCounterType get_count(HashIntoType khash) const
    {
        for (size_t i = 0; i < _n_tables; i++) {
            uint64_t bin = khash % _tablesizes[i];
            uint64_t byte = bin / 8;
            unsigned char bit = bin % 8;

            if (!(_counts[i][byte] & (1 << bit))) {
                return 0;
            }
        }
        return 1;
    }

    // Writing to the tables outside of defined methods has undefined behavior!
    // As such, this should only be used to return read-only interfaces
    Byte ** get_raw_tables()
    {
        return _counts;
    }

    void update_from(const BitStorage&);
};

/*
 * \class ByteStorage
 *
 * \brief A CountMin sketch implementation.
 *
 * ByteStorage is used to track counts of k-mers by Hashtable
 * and derived classes.  It contains 'n_tables' different tables of
 * bytesizes specified in 'tablesizes'.
 *
 * Like other Storage classes, ByteStorage manages setting the bits and
 * tracking statistics, as well as save/load, and not much else.
 *
 */

class CountingHashFile;
class CountingHashFileReader;
class CountingHashFileWriter;
class CountingHashGzFileReader;
class CountingHashGzFileWriter;

class ByteStorage : public Storage {
    friend class CountingHashFile;
    friend class CountingHashFileReader;
    friend class CountingHashFileWriter;
    friend class CountingHashGzFileReader;
    friend class CountingHashGzFileWriter;
    friend class CountingHash;
protected:
    unsigned int    _max_count;
    unsigned int    _max_bigcount;

    uint32_t _bigcount_spin_lock;
    std::vector<uint64_t> _tablesizes;
    size_t _n_tables;
    uint64_t _n_unique_kmers;
    uint64_t _occupied_bins;

    Byte ** _counts;

    // initialize counts with empty hashtables.
    void _allocate_counters()
    {
        _n_tables = _tablesizes.size();

        _counts = new Byte*[_n_tables];
        for (size_t i = 0; i < _n_tables; i++) {
            _counts[i] = new Byte[_tablesizes[i]];
            memset(_counts[i], 0, _tablesizes[i]);
        }
    }
public:
    KmerCountMap _bigcounts;

    // constructor: create an empty CountMin sketch.
    ByteStorage(std::vector<uint64_t>& tablesizes ) :
        _max_count(MAX_KCOUNT), _max_bigcount(MAX_BIGCOUNT),
        _bigcount_spin_lock(false), _tablesizes(tablesizes),
        _n_unique_kmers(0), _occupied_bins(0)
    {

        _allocate_counters();
    }

    // destructor: clear out the memory.
    ~ByteStorage()
    {
        if (_counts) {
            for (size_t i = 0; i < _n_tables; i++) {
                if (_counts[i]) {
                    delete[] _counts[i];
                    _counts[i] = NULL;
                }
            }

            delete[] _counts;
            _counts = NULL;

            _n_tables = 0;
        }
    }

    std::vector<uint64_t> get_tablesizes() const { return _tablesizes; }

    const uint64_t n_unique_kmers() const { return _n_unique_kmers; }
    const size_t n_tables() const { return _n_tables; }
    const uint64_t n_occupied() const { return _occupied_bins; }

    void save(std::string, WordLength);
    void load(std::string, WordLength&);

    inline BoundedCounterType test_and_set_bits(HashIntoType khash)
    {
        BoundedCounterType x = get_count(khash);
        add(khash);
        return !x;
    }

    inline void add(HashIntoType khash)
    {
        bool is_new_kmer = false;
        unsigned int  n_full	  = 0;

        // add one to each entry in each table.
        for (unsigned int i = 0; i < _n_tables; i++) {
            const uint64_t bin = khash % _tablesizes[i];
            Byte current_count = _counts[ i ][ bin ];
            if (!is_new_kmer) {
                if (current_count == 0) {
                    is_new_kmer = true;

                    // track occupied bins in the first table only, as proxy
                    // for all.
                    if (i == 0) {
                        __sync_add_and_fetch(&_occupied_bins, 1);
                    }
                }
            }
            // NOTE: Technically, multiple threads can cause the bin to spill
            //	 over max_count a little, if they all read it as less than
            //	 max_count before any of them increment it.
            //	 However, do we actually care if there is a little
            //	 bit of slop here? It can always be trimmed off later, if
            //	 that would help with stats.

            if ( _max_count > current_count ) {
                __sync_add_and_fetch( *(_counts + i) + bin, 1 );
            } else {
                n_full++;
            }
        } // for each table

        // if all tables are full for this position, then add in bigcounts.
        if (n_full == _n_tables && _use_bigcount) {
            while (!__sync_bool_compare_and_swap(&_bigcount_spin_lock, 0, 1));
            if (_bigcounts[khash] == 0) {
                _bigcounts[khash] = _max_count + 1;
            } else {
                if (_bigcounts[khash] < _max_bigcount) {
                    _bigcounts[khash] += 1;
                }
            }
            __sync_bool_compare_and_swap( &_bigcount_spin_lock, 1, 0 );
        }

        if (is_new_kmer) {
            __sync_add_and_fetch(&_n_unique_kmers, 1);
        }

    }

    // get the count for the given k-mer hash.
    inline const BoundedCounterType get_count(HashIntoType khash) const
    {
        unsigned int	  max_count	= _max_count;
        BoundedCounterType  min_count	= max_count; // bound count by max.

        // first, get the min count across all tables (standard CMS).
        for (unsigned int i = 0; i < _n_tables; i++) {
            BoundedCounterType the_count = _counts[i][khash % _tablesizes[i]];
            if (the_count < min_count) {
                min_count = the_count;
            }
        }

        // if the count is saturated, check in the bigcount structure to
        // see if we've accumulated more counts.
        if (min_count == max_count && _use_bigcount) {
            KmerCountMap::const_iterator it = _bigcounts.find(khash);
            if (it != _bigcounts.end()) {
                min_count = it->second;
            }
        }
        return min_count;
    }
    // Get direct access to the counts.
    //
    // Note:
    // Writing to the tables outside of defined methods has undefined behavior!
    // As such, this should only be used to return read-only interfaces
    Byte ** get_raw_tables()
    {
        return _counts;
    }

};

// Helper classes for saving ByteStorage objs to disk & loading them.

class CountingHashFile
{
public:
    static void load(const std::string &infilename,
                     WordLength &ksize,
                     ByteStorage &store);
    static void save(const std::string &outfilename,
                     const WordLength ksize,
                     const ByteStorage &store);
};

class CountingHashFileReader : public CountingHashFile
{
public:
    CountingHashFileReader(const std::string &infilename,
                           WordLength &ksize,
                           ByteStorage &store);
};

class CountingHashGzFileReader : public CountingHashFile
{
public:
    CountingHashGzFileReader(const std::string &infilename,
                             WordLength &ksize,
                             ByteStorage &store);
};

class CountingHashFileWriter : public CountingHashFile
{
public:
    CountingHashFileWriter(const std::string &outfilename,
                           const WordLength ksize,
                           const ByteStorage &store);
};

class CountingHashGzFileWriter : public CountingHashFile
{
public:
    CountingHashGzFileWriter(const std::string &outfilename,
                             const WordLength ksize,
                             const ByteStorage &store);
};
}

#endif // STORAGE_HH
<|endoftext|>


<commit_before>/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

#include <signal.h>
#include <unistd.h>

#include <mutex>

#include <event2/event.h>
#include <event2/thread.h>
#include <event2/util.h>

#include <process/logging.hpp>
#include <process/once.hpp>

#include <stout/os/signals.hpp>
#include <stout/synchronized.hpp>
#include <stout/thread_local.hpp>

#include "event_loop.hpp"
#include "libevent.hpp"

namespace process {

event_base* base = NULL;

static std::mutex* functions_mutex = new std::mutex();
std::queue<lambda::function<void(void)>>* functions =
  new std::queue<lambda::function<void(void)>>();

THREAD_LOCAL bool* _in_event_loop_ = NULL;

void async_function(int socket, short which, void* arg)
{
  event* ev = reinterpret_cast<event*>(arg);
  event_free(ev);

  std::queue<lambda::function<void(void)>> q;

  synchronized (functions_mutex) {
    std::swap(q, *functions);
  }

  while (!q.empty()) {
    q.front()();
    q.pop();
  }
}

void run_in_event_loop(
    const lambda::function<void(void)>& f,
    EventLoopLogicFlow event_loop_logic_flow)
{
  if (__in_event_loop__ && event_loop_logic_flow == ALLOW_SHORT_CIRCUIT) {
    f();
    return;
  }

  synchronized (functions_mutex) {
    functions->push(f);

    // Add an event and activate it to interrupt the event loop.
    // TODO(jmlvanre): after libevent v 2.1 we can use
    // event_self_cbarg instead of re-assigning the event. For now we
    // manually re-assign the event to pass in the pointer to the
    // event itself as the callback argument.
    event* ev = evtimer_new(base, async_function, NULL);

    // 'event_assign' is only valid on non-pending AND non-active
    // events. This means we have to assign the callback before
    // calling 'event_active'.
    if (evtimer_assign(ev, base, async_function, ev) < 0) {
      LOG(FATAL) << "Failed to assign callback on event";
    }

    event_active(ev, EV_TIMEOUT, 0);
  }
}

void EventLoop::run()
{
  __in_event_loop__ = true;

  // Block SIGPIPE in the event loop because we can not force
  // underlying implementations such as SSL bufferevents to use
  // MSG_NOSIGNAL.
  bool unblock = os::signals::block(SIGPIPE);

  do {
    int result = event_base_loop(base, EVLOOP_ONCE);
    if (result < 0) {
      LOG(FATAL) << "Failed to run event loop";
    } else if (result > 0) {
      // All events are handled, continue event loop.
      continue;
    } else {
      CHECK_EQ(0, result);
      if (event_base_got_break(base)) {
        break;
      } else if (event_base_got_exit(base)) {
        break;
      }
    }
  } while (true);

  __in_event_loop__ = false;

  if (unblock) {
    if (!os::signals::unblock(SIGPIPE)) {
      LOG(FATAL) << "Failure to unblock SIGPIPE";
    }
  }
}

void EventLoop::stop()
{
  event_base_loopexit(base, NULL);
}

namespace internal {

struct Delay
{
  lambda::function<void(void)> function;
  event* timer;
};

void handle_delay(int, short, void* arg)
{
  Delay* delay = reinterpret_cast<Delay*>(arg);
  delay->function();
  event_free(delay->timer);
  delete delay;
}

}  // namespace internal {

void EventLoop::delay(
    const Duration& duration,
    const lambda::function<void(void)>& function)
{
  internal::Delay* delay = new internal::Delay();
  delay->timer = evtimer_new(base, &internal::handle_delay, delay);
  if (delay->timer == NULL) {
    LOG(FATAL) << "Failed to delay, evtimer_new";
  }

  delay->function = function;

  timeval t{0, 0};
  if (duration > Seconds(0)) {
    t = duration.timeval();
  }

  evtimer_add(delay->timer, &t);
}

double EventLoop::time()
{
  // We explicitly call `evutil_gettimeofday()` for now to avoid any
  // issues that may be introduced by using the cached value provided
  // by `event_base_gettimeofday_cached()`. Since a lot of logic in
  // libprocess depends on time math, we want to log fatal rather than
  // cause logic errors if the time fails.
  timeval t;
  if (evutil_gettimeofday(&t, NULL) < 0) {
    LOG(FATAL) << "Failed to get time, evutil_gettimeofday";
  }

  return Duration(t).secs();
}

void EventLoop::initialize()
{
  static Once* initialized = new Once();

  if (initialized->once()) {
    return;
  }

  // We need to initialize Libevent differently depending on the
  // operating system threading support.
#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
  if (evthread_use_pthreads() < 0) {
    LOG(FATAL) << "Failed to initialize, evthread_use_pthreads";
  }
#elif defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
  if (evthread_use_windows_threads() < 0) {
    LOG(FATAL) << "Failed to initialize, evthread_use_windows_threads";
  }
#else
#error "Libevent must be compiled with either pthread or Windows thread support"
#endif

  // This enables debugging of libevent calls. We can remove this
  // when the implementation settles and after we gain confidence.
  event_enable_debug_mode();

  // TODO(jmlvanre): Allow support for 'epoll' once SSL related
  // issues are resolved.
  struct event_config* config = event_config_new();
  event_config_avoid_method(config, "epoll");

  base = event_base_new_with_config(config);

  if (base == NULL) {
    LOG(FATAL) << "Failed to initialize, event_base_new";
  }

  initialized->done();
}

} // namespace process {
<commit_msg>Ignore SIGPIPE in libevent execution thread using SUPPRESS.<commit_after>/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

#include <signal.h>
#include <unistd.h>

#include <mutex>

#include <event2/event.h>
#include <event2/thread.h>
#include <event2/util.h>

#include <process/logging.hpp>
#include <process/once.hpp>

#include <stout/os/signals.hpp>
#include <stout/synchronized.hpp>
#include <stout/thread_local.hpp>

#include "event_loop.hpp"
#include "libevent.hpp"

namespace process {

event_base* base = NULL;

static std::mutex* functions_mutex = new std::mutex();
std::queue<lambda::function<void(void)>>* functions =
  new std::queue<lambda::function<void(void)>>();

THREAD_LOCAL bool* _in_event_loop_ = NULL;

void async_function(int socket, short which, void* arg)
{
  event* ev = reinterpret_cast<event*>(arg);
  event_free(ev);

  std::queue<lambda::function<void(void)>> q;

  synchronized (functions_mutex) {
    std::swap(q, *functions);
  }

  while (!q.empty()) {
    q.front()();
    q.pop();
  }
}

void run_in_event_loop(
    const lambda::function<void(void)>& f,
    EventLoopLogicFlow event_loop_logic_flow)
{
  if (__in_event_loop__ && event_loop_logic_flow == ALLOW_SHORT_CIRCUIT) {
    f();
    return;
  }

  synchronized (functions_mutex) {
    functions->push(f);

    // Add an event and activate it to interrupt the event loop.
    // TODO(jmlvanre): after libevent v 2.1 we can use
    // event_self_cbarg instead of re-assigning the event. For now we
    // manually re-assign the event to pass in the pointer to the
    // event itself as the callback argument.
    event* ev = evtimer_new(base, async_function, NULL);

    // 'event_assign' is only valid on non-pending AND non-active
    // events. This means we have to assign the callback before
    // calling 'event_active'.
    if (evtimer_assign(ev, base, async_function, ev) < 0) {
      LOG(FATAL) << "Failed to assign callback on event";
    }

    event_active(ev, EV_TIMEOUT, 0);
  }
}

void EventLoop::run()
{
  __in_event_loop__ = true;

  // Block SIGPIPE in the event loop because we can not force
  // underlying implementations such as SSL bufferevents to use
  // MSG_NOSIGNAL.
  SUPPRESS(SIGPIPE) {
    do {
      int result = event_base_loop(base, EVLOOP_ONCE);
      if (result < 0) {
        LOG(FATAL) << "Failed to run event loop";
      } else if (result > 0) {
        // All events are handled, continue event loop.
        continue;
      } else {
        CHECK_EQ(0, result);
        if (event_base_got_break(base)) {
          break;
        } else if (event_base_got_exit(base)) {
          break;
        }
      }
    } while (true);
  }

  __in_event_loop__ = false;
}

void EventLoop::stop()
{
  event_base_loopexit(base, NULL);
}

namespace internal {

struct Delay
{
  lambda::function<void(void)> function;
  event* timer;
};

void handle_delay(int, short, void* arg)
{
  Delay* delay = reinterpret_cast<Delay*>(arg);
  delay->function();
  event_free(delay->timer);
  delete delay;
}

}  // namespace internal {

void EventLoop::delay(
    const Duration& duration,
    const lambda::function<void(void)>& function)
{
  internal::Delay* delay = new internal::Delay();
  delay->timer = evtimer_new(base, &internal::handle_delay, delay);
  if (delay->timer == NULL) {
    LOG(FATAL) << "Failed to delay, evtimer_new";
  }

  delay->function = function;

  timeval t{0, 0};
  if (duration > Seconds(0)) {
    t = duration.timeval();
  }

  evtimer_add(delay->timer, &t);
}

double EventLoop::time()
{
  // We explicitly call `evutil_gettimeofday()` for now to avoid any
  // issues that may be introduced by using the cached value provided
  // by `event_base_gettimeofday_cached()`. Since a lot of logic in
  // libprocess depends on time math, we want to log fatal rather than
  // cause logic errors if the time fails.
  timeval t;
  if (evutil_gettimeofday(&t, NULL) < 0) {
    LOG(FATAL) << "Failed to get time, evutil_gettimeofday";
  }

  return Duration(t).secs();
}

void EventLoop::initialize()
{
  static Once* initialized = new Once();

  if (initialized->once()) {
    return;
  }

  // We need to initialize Libevent differently depending on the
  // operating system threading support.
#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
  if (evthread_use_pthreads() < 0) {
    LOG(FATAL) << "Failed to initialize, evthread_use_pthreads";
  }
#elif defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
  if (evthread_use_windows_threads() < 0) {
    LOG(FATAL) << "Failed to initialize, evthread_use_windows_threads";
  }
#else
#error "Libevent must be compiled with either pthread or Windows thread support"
#endif

  // This enables debugging of libevent calls. We can remove this
  // when the implementation settles and after we gain confidence.
  event_enable_debug_mode();

  // TODO(jmlvanre): Allow support for 'epoll' once SSL related
  // issues are resolved.
  struct event_config* config = event_config_new();
  event_config_avoid_method(config, "epoll");

  base = event_base_new_with_config(config);

  if (base == NULL) {
    LOG(FATAL) << "Failed to initialize, event_base_new";
  }

  initialized->done();
}

} // namespace process {
<|endoftext|>


<commit_before>/*
 * gallerytiltshiftwidget.cpp
 *
 * Copyright (C) 2012 Igalia, S.L.
 * Author: Simon Pena <spena@igalia.com>
 *
 * This file is part of the Gallery Tilt Shift Plugin.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see http://www.gnu.org/licenses/ *
 */

#include "gallerytiltshiftwidget.h"
#include "gallerytiltshiftwidget_p.h"
#include "gallerytiltshiftaboutwidget.h"

#include <MApplication>
#include <MButton>
#include <MButtonGroup>
#include <MLabel>
#include <MLayout>
#include <MLinearLayoutPolicy>
#include <MSeparator>
#include <MSlider>
#include <MWidgetController>
#include <MWidgetCreator>
#include <QGraphicsLinearLayout>

M_REGISTER_WIDGET_NO_CREATE(GalleryTiltShiftWidget)

GalleryTiltShiftWidgetPrivate::GalleryTiltShiftWidgetPrivate() :
    m_applyHorizontallyButton(0),
    m_applyVerticallyButton(0),
    m_buttonGroup(new MButtonGroup),
    m_slider(0),
    m_orientationLayout(new MLayout),
    m_landscapePolicy(new MLinearLayoutPolicy(m_orientationLayout, Qt::Horizontal)),
    m_portraitPolicy(new MLinearLayoutPolicy(m_orientationLayout, Qt::Vertical)),
    m_aboutSeparator(new MSeparator),
    m_aboutWidget(new GalleryTiltShiftAboutWidget)
{
    m_orientationLayout->setContentsMargins(0, 0, 0, 0);
    m_orientationLayout->setAnimation(0);

    m_landscapePolicy->setContentsMargins(128, 0, 128, 0);
    m_landscapePolicy->setNotifyWidgetsOfLayoutPositionEnabled(true);
    m_landscapePolicy->setSpacing(0);

    m_portraitPolicy->setContentsMargins(64, 0, 64, 0);
    m_portraitPolicy->setNotifyWidgetsOfLayoutPositionEnabled(true);
    m_portraitPolicy->setSpacing(0);

    m_orientationLayout->setLandscapePolicy(m_landscapePolicy);
    m_orientationLayout->setPortraitPolicy(m_portraitPolicy);

    m_aboutSeparator->setStyleName("CommonHeaderDividerInverted");
}

GalleryTiltShiftWidgetPrivate::~GalleryTiltShiftWidgetPrivate()
{
    delete m_applyHorizontallyButton;
    delete m_applyVerticallyButton;
    delete m_buttonGroup;
    delete m_slider;
    delete m_portraitPolicy;
    delete m_landscapePolicy;
    delete m_aboutSeparator;
    delete m_aboutWidget;
}

MButton* GalleryTiltShiftWidgetPrivate::addButton(const QString& label,
                                                  const QString& objectName,
                                                  const QString& styleName)
{
    MButton* button = new MButton(label);
    button->setObjectName(objectName);
    button->setCheckable(true);
    button->setStyleName(styleName);

    m_buttonGroup->addButton(button);
    m_landscapePolicy->addItem(button);
    m_portraitPolicy->addItem(button, Qt::AlignCenter);

    return button;
}

GalleryTiltShiftWidget::GalleryTiltShiftWidget(QGraphicsItem* parent) :
    MWidgetController(parent),
    d_ptr(new GalleryTiltShiftWidgetPrivate)
{
    setObjectName("GalleryTiltShiftWidget");
    setStyleName("ImageEditorBcControl");
    setContentsMargins(0, 0, 0, 0);

    Q_D(GalleryTiltShiftWidget);
    d->m_slider = new MSlider();
    d->m_slider->setStyleName("CommonSliderInverted");
    d->m_slider->setObjectName("TiltShiftAreaSlider");
    d->m_slider->setRange(5, 30);
    d->m_slider->setValue(15);

    connect(d->m_slider, SIGNAL(valueChanged(int)),
            SLOT(handleValueChanged(int)));
    connect(d->m_slider, SIGNAL(sliderPressed()),
            SLOT(showSliderHandle()));
    connect(d->m_slider, SIGNAL(sliderReleased()),
            SLOT(hideSliderHandle()));

    d->m_applyHorizontallyButton = d->addButton("Apply Horizontally",
                                                "ApplyHorizontallyButton",
                                                "CommonTopSplitButtonInverted");

    d->m_applyVerticallyButton = d->addButton("Apply Vertically",
                                              "ApplyVerticallyButton",
                                              "CommonBottomSplitButtonInverted");

    // TODO: Is there another way to have a MButton in a MButtonGroup selected?
    d->m_applyHorizontallyButton->click();

    connect(d->m_applyHorizontallyButton, SIGNAL(clicked()),
            SLOT(onApplyHorizontallyButtonClicked()));
    connect(d->m_applyVerticallyButton, SIGNAL(clicked()),
            SLOT(onApplyVerticallyButtonClicked()));
    connect(d->m_aboutWidget, SIGNAL(linkActivated(QString)),
            SIGNAL(aboutLinkActivated(QString)));

    QGraphicsLinearLayout* mainLayout = new QGraphicsLinearLayout(Qt::Vertical);
    mainLayout->setContentsMargins(0, 0, 0, 0);
    mainLayout->setSpacing(0);
    mainLayout->addItem(d->m_slider);
    mainLayout->setAlignment(d->m_slider, Qt::AlignCenter);
    mainLayout->addItem(d->m_orientationLayout);
    mainLayout->setAlignment(d->m_orientationLayout, Qt::AlignCenter);
    mainLayout->addItem(d->m_aboutSeparator);
    mainLayout->addItem(d->m_aboutWidget);

    setLayout(mainLayout);

    // Make sure initial policy is correct
    if (MApplication::activeWindow()) {
        if (MApplication::activeWindow()->orientation() == M::Portrait) {
            d->m_portraitPolicy->activate();
        } else {
            d->m_landscapePolicy->activate();
        }
    } else {
        d->m_landscapePolicy->activate();
    }
}

GalleryTiltShiftWidget::~GalleryTiltShiftWidget()
{
    delete d_ptr;
    d_ptr = 0;
}

int GalleryTiltShiftWidget::sliderValue() const
{
    Q_D(const GalleryTiltShiftWidget);
    return d->m_slider->value();
}

bool GalleryTiltShiftWidget::isSliderHandleLabelVisible() const
{
    Q_D(const GalleryTiltShiftWidget);
    return d->m_slider->isHandleLabelVisible();
}

Qt::Orientation GalleryTiltShiftWidget::applicationOrientation() const
{
    Q_D(const GalleryTiltShiftWidget);
    if (d->m_buttonGroup->checkedButton() == d->m_applyHorizontallyButton) {
        return Qt::Horizontal;
    } else {
        return Qt::Vertical;
    }
}

void GalleryTiltShiftWidget::onApplyHorizontallyButtonClicked()
{
    emit applicationOrientationChanged();
}

void GalleryTiltShiftWidget::onApplyVerticallyButtonClicked()
{
    emit applicationOrientationChanged();
}

void GalleryTiltShiftWidget::showSliderHandle()
{
    Q_D(GalleryTiltShiftWidget);
    d->m_slider->setHandleLabelVisible(true);
    emit sliderHandleVisibilityChanged();
}

void GalleryTiltShiftWidget::hideSliderHandle()
{
    Q_D(GalleryTiltShiftWidget);
    d->m_slider->setHandleLabelVisible(false);
    emit sliderHandleVisibilityChanged();
    emit sliderValueChanged();
}

void GalleryTiltShiftWidget::handleValueChanged(int newValue)
{
    Q_UNUSED(newValue)
}

void GalleryTiltShiftWidget::setSliderHandleText(const QString& text)
{
    Q_D(GalleryTiltShiftWidget);
    d->m_slider->setHandleLabel(text);
}
<commit_msg>Priv Widget to delete all its widgets on destruct.<commit_after>/*
 * gallerytiltshiftwidget.cpp
 *
 * Copyright (C) 2012 Igalia, S.L.
 * Author: Simon Pena <spena@igalia.com>
 *
 * This file is part of the Gallery Tilt Shift Plugin.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see http://www.gnu.org/licenses/ *
 */

#include "gallerytiltshiftwidget.h"
#include "gallerytiltshiftwidget_p.h"
#include "gallerytiltshiftaboutwidget.h"

#include <MApplication>
#include <MButton>
#include <MButtonGroup>
#include <MLabel>
#include <MLayout>
#include <MLinearLayoutPolicy>
#include <MSeparator>
#include <MSlider>
#include <MWidgetController>
#include <MWidgetCreator>
#include <QGraphicsLinearLayout>

M_REGISTER_WIDGET_NO_CREATE(GalleryTiltShiftWidget)

GalleryTiltShiftWidgetPrivate::GalleryTiltShiftWidgetPrivate() :
    m_applyHorizontallyButton(0),
    m_applyVerticallyButton(0),
    m_buttonGroup(new MButtonGroup),
    m_slider(0),
    m_orientationLayout(new MLayout),
    m_landscapePolicy(new MLinearLayoutPolicy(m_orientationLayout, Qt::Horizontal)),
    m_portraitPolicy(new MLinearLayoutPolicy(m_orientationLayout, Qt::Vertical)),
    m_aboutSeparator(new MSeparator),
    m_aboutWidget(new GalleryTiltShiftAboutWidget)
{
    m_orientationLayout->setContentsMargins(0, 0, 0, 0);
    m_orientationLayout->setAnimation(0);

    m_landscapePolicy->setContentsMargins(128, 0, 128, 0);
    m_landscapePolicy->setNotifyWidgetsOfLayoutPositionEnabled(true);
    m_landscapePolicy->setSpacing(0);

    m_portraitPolicy->setContentsMargins(64, 0, 64, 0);
    m_portraitPolicy->setNotifyWidgetsOfLayoutPositionEnabled(true);
    m_portraitPolicy->setSpacing(0);

    m_orientationLayout->setLandscapePolicy(m_landscapePolicy);
    m_orientationLayout->setPortraitPolicy(m_portraitPolicy);

    m_aboutSeparator->setStyleName("CommonHeaderDividerInverted");
}

GalleryTiltShiftWidgetPrivate::~GalleryTiltShiftWidgetPrivate()
{
    delete m_applyHorizontallyButton;
    delete m_applyVerticallyButton;
    delete m_buttonGroup;
    delete m_slider;
    delete m_portraitPolicy;
    delete m_landscapePolicy;
    delete m_orientationLayout;
    delete m_aboutSeparator;
    delete m_aboutWidget;
}

MButton* GalleryTiltShiftWidgetPrivate::addButton(const QString& label,
                                                  const QString& objectName,
                                                  const QString& styleName)
{
    MButton* button = new MButton(label);
    button->setObjectName(objectName);
    button->setCheckable(true);
    button->setStyleName(styleName);

    m_buttonGroup->addButton(button);
    m_landscapePolicy->addItem(button);
    m_portraitPolicy->addItem(button, Qt::AlignCenter);

    return button;
}

GalleryTiltShiftWidget::GalleryTiltShiftWidget(QGraphicsItem* parent) :
    MWidgetController(parent),
    d_ptr(new GalleryTiltShiftWidgetPrivate)
{
    setObjectName("GalleryTiltShiftWidget");
    setStyleName("ImageEditorBcControl");
    setContentsMargins(0, 0, 0, 0);

    Q_D(GalleryTiltShiftWidget);
    d->m_slider = new MSlider();
    d->m_slider->setStyleName("CommonSliderInverted");
    d->m_slider->setObjectName("TiltShiftAreaSlider");
    d->m_slider->setRange(5, 30);
    d->m_slider->setValue(15);

    connect(d->m_slider, SIGNAL(valueChanged(int)),
            SLOT(handleValueChanged(int)));
    connect(d->m_slider, SIGNAL(sliderPressed()),
            SLOT(showSliderHandle()));
    connect(d->m_slider, SIGNAL(sliderReleased()),
            SLOT(hideSliderHandle()));

    d->m_applyHorizontallyButton = d->addButton("Apply Horizontally",
                                                "ApplyHorizontallyButton",
                                                "CommonTopSplitButtonInverted");

    d->m_applyVerticallyButton = d->addButton("Apply Vertically",
                                              "ApplyVerticallyButton",
                                              "CommonBottomSplitButtonInverted");

    // TODO: Is there another way to have a MButton in a MButtonGroup selected?
    d->m_applyHorizontallyButton->click();

    connect(d->m_applyHorizontallyButton, SIGNAL(clicked()),
            SLOT(onApplyHorizontallyButtonClicked()));
    connect(d->m_applyVerticallyButton, SIGNAL(clicked()),
            SLOT(onApplyVerticallyButtonClicked()));
    connect(d->m_aboutWidget, SIGNAL(linkActivated(QString)),
            SIGNAL(aboutLinkActivated(QString)));

    QGraphicsLinearLayout* mainLayout = new QGraphicsLinearLayout(Qt::Vertical);
    mainLayout->setContentsMargins(0, 0, 0, 0);
    mainLayout->setSpacing(0);
    mainLayout->addItem(d->m_slider);
    mainLayout->setAlignment(d->m_slider, Qt::AlignCenter);
    mainLayout->addItem(d->m_orientationLayout);
    mainLayout->setAlignment(d->m_orientationLayout, Qt::AlignCenter);
    mainLayout->addItem(d->m_aboutSeparator);
    mainLayout->addItem(d->m_aboutWidget);

    setLayout(mainLayout);

    // Make sure initial policy is correct
    if (MApplication::activeWindow()) {
        if (MApplication::activeWindow()->orientation() == M::Portrait) {
            d->m_portraitPolicy->activate();
        } else {
            d->m_landscapePolicy->activate();
        }
    } else {
        d->m_landscapePolicy->activate();
    }
}

GalleryTiltShiftWidget::~GalleryTiltShiftWidget()
{
    delete d_ptr;
    d_ptr = 0;
}

int GalleryTiltShiftWidget::sliderValue() const
{
    Q_D(const GalleryTiltShiftWidget);
    return d->m_slider->value();
}

bool GalleryTiltShiftWidget::isSliderHandleLabelVisible() const
{
    Q_D(const GalleryTiltShiftWidget);
    return d->m_slider->isHandleLabelVisible();
}

Qt::Orientation GalleryTiltShiftWidget::applicationOrientation() const
{
    Q_D(const GalleryTiltShiftWidget);
    if (d->m_buttonGroup->checkedButton() == d->m_applyHorizontallyButton) {
        return Qt::Horizontal;
    } else {
        return Qt::Vertical;
    }
}

void GalleryTiltShiftWidget::onApplyHorizontallyButtonClicked()
{
    emit applicationOrientationChanged();
}

void GalleryTiltShiftWidget::onApplyVerticallyButtonClicked()
{
    emit applicationOrientationChanged();
}

void GalleryTiltShiftWidget::showSliderHandle()
{
    Q_D(GalleryTiltShiftWidget);
    d->m_slider->setHandleLabelVisible(true);
    emit sliderHandleVisibilityChanged();
}

void GalleryTiltShiftWidget::hideSliderHandle()
{
    Q_D(GalleryTiltShiftWidget);
    d->m_slider->setHandleLabelVisible(false);
    emit sliderHandleVisibilityChanged();
    emit sliderValueChanged();
}

void GalleryTiltShiftWidget::handleValueChanged(int newValue)
{
    Q_UNUSED(newValue)
}

void GalleryTiltShiftWidget::setSliderHandleText(const QString& text)
{
    Q_D(GalleryTiltShiftWidget);
    d->m_slider->setHandleLabel(text);
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkQtChartSeriesModelRange.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

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

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/

/// \file vtkQtChartSeriesModelRange.cxx
/// \date February 19, 2008

#ifdef _MSC_VER
// Disable warnings that Qt headers give.
#pragma warning(disable:4127)
#endif

#include "vtkQtChartSeriesModelRange.h"

#include "vtkQtChartSeriesModel.h"
#include <QDate>
#include <QDateTime>
#include <QTime>

vtkQtChartSeriesModelRange::vtkQtChartSeriesModelRange(QObject *parentObject)
  : QObject(parentObject)
{
  this->Model = 0;
  this->XRangeShared = false;
}

void vtkQtChartSeriesModelRange::setModel(vtkQtChartSeriesModel *model,
    bool xShared)
{
  if(this->Model != model)
    {
    if(this->Model)
      {
      this->disconnect(this->Model, 0, this, 0);
      }

    this->Model = model;
    if(this->Model)
      {
      // Use the series change signals to update the ranges.
      this->connect(this->Model, SIGNAL(modelReset()),
          this, SLOT(resetSeries()));
      this->connect(this->Model, SIGNAL(seriesInserted(int, int)),
          this, SLOT(insertSeries(int, int)));
      this->connect(this->Model, SIGNAL(seriesRemoved(int, int)),
          this, SLOT(removeSeries(int, int)));
      }

    this->XRangeShared = xShared;
    this->resetSeries();
    }
  else if(this->XRangeShared != xShared)
    {
    this->XRangeShared = xShared;
    this->resetSeries();
    }
}

QList<QVariant> vtkQtChartSeriesModelRange::getSeriesRange(int series,
    int component) const
{
  if(series >= 0 && series < this->Range[1].size())
    {
    if(component == 0 && this->XRangeShared)
      {
      series = 0;
      }

    return this->Range[component][series];
    }

  return QList<QVariant>();
}

void vtkQtChartSeriesModelRange::resetSeries()
{
  // Clean up the range information.
  this->Range[0].clear();
  this->Range[1].clear();

  // Add the new model series.
  if(this->Model)
    {
    int total = this->Model->getNumberOfSeries();
    if(total > 0)
      {
      this->insertSeries(0, total - 1);
      }
    }
}

void vtkQtChartSeriesModelRange::insertSeries(int first, int last)
{
  if(this->Model)
    {
    // Add range entries for the series.
    if(this->XRangeShared && this->Range[1].size() == 0)
      {
      this->Range[0].append(this->computeSeriesRange(0, 0));
      }

    for( ; first <= last; first++)
      {
      this->Range[1].insert(first, this->computeSeriesRange(first, 1));
      if(!this->XRangeShared)
        {
        this->Range[0].insert(first, this->computeSeriesRange(first, 0));
        }
      }
    }
}

void vtkQtChartSeriesModelRange::removeSeries(int first, int last)
{
  // Remove range entries for the series.
  for( ; last >= first; last--)
    {
    this->Range[1].removeAt(last);
    if(!this->XRangeShared)
      {
      this->Range[0].removeAt(last);
      }
    }

  if(this->XRangeShared && this->Range[1].size() == 0)
    {
    this->Range[0].clear();
    }
}

QList<QVariant> vtkQtChartSeriesModelRange::computeSeriesRange(int series,
    int component)
{
  QList<QVariant> range;
  if(this->Model)
    {
    int total = this->Model->getNumberOfSeriesValues(series);
    if(total > 0)
      {
      // Use the first value to determine the type.
      QVariant value = this->Model->getSeriesValue(series, 0, component);
      QVariant::Type valueType = value.type();
      if(valueType == QVariant::String)
        {
        return range;
        }

      range.append(value);
      range.append(value);
      for(int i = 1; i < total; i++)
        {
        value = this->Model->getSeriesValue(series, i, component);
        if(value.type() != valueType)
          {
          continue;
          }

        if(valueType == QVariant::Int)
          {
          range[0] = qMin<int>(value.toInt(), range[0].toInt());
          range[1] = qMax<int>(value.toInt(), range[1].toInt());
          }
        else if(valueType == QVariant::Double)
          {
          range[0] = qMin<double>(value.toDouble(), range[0].toDouble());
          range[1] = qMax<double>(value.toDouble(), range[1].toDouble());
          }
        else if(valueType == QVariant::Date)
          {
          range[0] = qMin<QDate>(value.toDate(), range[0].toDate());
          range[1] = qMax<QDate>(value.toDate(), range[1].toDate());
          }
        else if(valueType == QVariant::DateTime)
          {
          range[0] = qMin<QDateTime>(value.toDateTime(),
              range[0].toDateTime());
          range[1] = qMax<QDateTime>(value.toDateTime(),
              range[1].toDateTime());
          }
        else if(valueType == QVariant::Time)
          {
          range[0] = qMin<QTime>(value.toTime(), range[0].toTime());
          range[1] = qMax<QTime>(value.toTime(), range[1].toTime());
          }
        }
      }
    }

  return range;
}

<commit_msg>ENH: Correctly handle range of data with NaN in it.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkQtChartSeriesModelRange.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

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

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/

/// \file vtkQtChartSeriesModelRange.cxx
/// \date February 19, 2008

#ifdef _MSC_VER
// Disable warnings that Qt headers give.
#pragma warning(disable:4127)
#endif

#include "vtkQtChartSeriesModelRange.h"

#include "vtkQtChartSeriesModel.h"
#include <QDate>
#include <QDateTime>
#include <QTime>

#include <math.h>

#ifndef isnan
// This is compiler specific not platform specific: MinGW doesn't need that.
# if defined(_MSC_VER) || defined(__BORLANDC__)
#  include <float.h>
#  define isnan(x) _isnan(x)
# endif
#endif

vtkQtChartSeriesModelRange::vtkQtChartSeriesModelRange(QObject *parentObject)
  : QObject(parentObject)
{
  this->Model = 0;
  this->XRangeShared = false;
}

void vtkQtChartSeriesModelRange::setModel(vtkQtChartSeriesModel *model,
    bool xShared)
{
  if(this->Model != model)
    {
    if(this->Model)
      {
      this->disconnect(this->Model, 0, this, 0);
      }

    this->Model = model;
    if(this->Model)
      {
      // Use the series change signals to update the ranges.
      this->connect(this->Model, SIGNAL(modelReset()),
          this, SLOT(resetSeries()));
      this->connect(this->Model, SIGNAL(seriesInserted(int, int)),
          this, SLOT(insertSeries(int, int)));
      this->connect(this->Model, SIGNAL(seriesRemoved(int, int)),
          this, SLOT(removeSeries(int, int)));
      }

    this->XRangeShared = xShared;
    this->resetSeries();
    }
  else if(this->XRangeShared != xShared)
    {
    this->XRangeShared = xShared;
    this->resetSeries();
    }
}

QList<QVariant> vtkQtChartSeriesModelRange::getSeriesRange(int series,
    int component) const
{
  if(series >= 0 && series < this->Range[1].size())
    {
    if(component == 0 && this->XRangeShared)
      {
      series = 0;
      }

    return this->Range[component][series];
    }

  return QList<QVariant>();
}

void vtkQtChartSeriesModelRange::resetSeries()
{
  // Clean up the range information.
  this->Range[0].clear();
  this->Range[1].clear();

  // Add the new model series.
  if(this->Model)
    {
    int total = this->Model->getNumberOfSeries();
    if(total > 0)
      {
      this->insertSeries(0, total - 1);
      }
    }
}

void vtkQtChartSeriesModelRange::insertSeries(int first, int last)
{
  if(this->Model)
    {
    // Add range entries for the series.
    if(this->XRangeShared && this->Range[1].size() == 0)
      {
      this->Range[0].append(this->computeSeriesRange(0, 0));
      }

    for( ; first <= last; first++)
      {
      this->Range[1].insert(first, this->computeSeriesRange(first, 1));
      if(!this->XRangeShared)
        {
        this->Range[0].insert(first, this->computeSeriesRange(first, 0));
        }
      }
    }
}

void vtkQtChartSeriesModelRange::removeSeries(int first, int last)
{
  // Remove range entries for the series.
  for( ; last >= first; last--)
    {
    this->Range[1].removeAt(last);
    if(!this->XRangeShared)
      {
      this->Range[0].removeAt(last);
      }
    }

  if(this->XRangeShared && this->Range[1].size() == 0)
    {
    this->Range[0].clear();
    }
}

QList<QVariant> vtkQtChartSeriesModelRange::computeSeriesRange(int series,
    int component)
{
  QList<QVariant> range;
  if(this->Model)
    {
    int total = this->Model->getNumberOfSeriesValues(series);
    int i;
    QVariant value;
    QVariant::Type valueType;

    // Find the first non-NULL, non-NaN value.  Use it to determine type
    // and initialize min/max values.
    for (i = 0; i < total; i++)
      {
      value = this->Model->getSeriesValue(series, i, component);
      valueType = value.type();
      // Check to see if the the value is invalid and we have to continue loop.
      if (value.isNull()) continue;
      if (!value.isValid()) continue;
      if ((valueType == QVariant::Double) && isnan(value.toDouble())) continue;
      // If we got here, we passed all the checks.  Break out.
      break;
      }

    // If we found a valid entry that is not a string (for which range has no
    // meaning), then continue to compute the range.
    if ((i < total) && (valueType != QVariant::String))
      {
      range.append(value);
      range.append(value);
      // Continue iteration over values.
      for(i++; i < total; i++)
        {
        value = this->Model->getSeriesValue(series, i, component);
        if(value.type() != valueType)
          {
          continue;
          }

        if(valueType == QVariant::Int)
          {
          range[0] = qMin<int>(value.toInt(), range[0].toInt());
          range[1] = qMax<int>(value.toInt(), range[1].toInt());
          }
        else if(valueType == QVariant::Double)
          {
          if (!isnan(value.toDouble()))
            {
            range[0] = qMin<double>(value.toDouble(), range[0].toDouble());
            range[1] = qMax<double>(value.toDouble(), range[1].toDouble());
            }
          }
        else if(valueType == QVariant::Date)
          {
          range[0] = qMin<QDate>(value.toDate(), range[0].toDate());
          range[1] = qMax<QDate>(value.toDate(), range[1].toDate());
          }
        else if(valueType == QVariant::DateTime)
          {
          range[0] = qMin<QDateTime>(value.toDateTime(),
              range[0].toDateTime());
          range[1] = qMax<QDateTime>(value.toDateTime(),
              range[1].toDateTime());
          }
        else if(valueType == QVariant::Time)
          {
          range[0] = qMin<QTime>(value.toTime(), range[0].toTime());
          range[1] = qMax<QTime>(value.toTime(), range[1].toTime());
          }
        }
      }
    }

  return range;
}

<|endoftext|>


<commit_before>/*
 * HackerRank CTCI Challenges
 * Stacks: Balanced Brackets
 * https://www.hackerrank.com/challenges/ctci-balanced-brackets
 *
 * Written by Zhen Zhi Lee in C++11
 * Last modified 27/01/2017
 */

#include <iostream>
#include <stack>

using namespace std;

bool isBalanced(string expression) {
    stack<char> checker;

    for (auto c : expression) {
        switch (c) {
            case '{':
            case '(':
            case '[':
                checker.push(c);
                break;
            case '}':
                if (!checker.empty() && checker.top() == '{') {
                    checker.pop();
                } else {
                    return false;
                }
                break;
            case ')':
                if (!checker.empty() && checker.top() == '(') {
                    checker.pop();
                } else {
                    return false;
                }
                break;
            case ']':
                if (!checker.empty() && checker.top() == '[') {
                    checker.pop();
                } else {
                    return false;
                }
                break;
            default:
                break;
        }
    }

    return checker.empty();
}

int main() {
    int numberOfExpressions;

    cin >> numberOfExpressions;

    for (auto i = 0; i < numberOfExpressions; ++i) {
        string expression;
        cin >> expression;
        cout << (isBalanced(expression) ? "YES" : "NO") << endl;
    }

    return 0;
}<commit_msg>Refactored BalancedBrackets<commit_after>/*
 * HackerRank CTCI Challenges
 * Stacks: Balanced Brackets
 * https://www.hackerrank.com/challenges/ctci-balanced-brackets
 *
 * Written by Zhen Zhi Lee in C++11
 * Last modified 27/01/2017
 */

#include <iostream>
#include <stack>

using namespace std;

bool isBalanced(string expression) {
    stack<char> checker;

    for (auto c : expression) {
        if (c == '{' || c == '(' || c == '[') {
            checker.push(c);
            continue;
        }

        if (checker.empty()) return false;

        auto bracket = checker.top();

        if (bracket == '{' && c == '}' ||
            bracket == '(' && c == ')' ||
            bracket == '[' && c == ']') {
            checker.pop();
        } else {
            return false;
        }
    }

    return checker.empty();
}

int main() {
    int numberOfExpressions;

    cin >> numberOfExpressions;

    for (auto i = 0; i < numberOfExpressions; ++i) {
        string expression;
        cin >> expression;
        cout << (isBalanced(expression) ? "YES" : "NO") << endl;
    }

    return 0;
}<|endoftext|>


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

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

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

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

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

#include "otbDEMConvertAdapter.h"

#include "itkImageIOFactory.h"

namespace otb
{
namespace Wrapper
{

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

  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(DEMConvert, otb::Application);

private:
  void DoInit()
  {
    SetName("DEMConvert");
    SetDescription("Converts a geo-referenced DEM image into a general raster file compatible with OTB DEM handling.");

    SetDocName("DEM Conversion");
    SetDocLongDescription("In order to be understood by the Orfeo ToolBox and the underlying OSSIM library, a geo-referenced Digital Elevation Model image can be converted into a general raster image, which consists in 3 files with the following extensions: .ras, .geom and .omd. Once converted, you have to place these files in a separate directory, and you can then use this directory to set the \"DEM Directory\" parameter of a DEM based OTB application or filter.");
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(" ");

    AddDocTag(Tags::Manip);

    AddParameter(ParameterType_InputImage,  "in",  "Input geo-referenced DEM");
    SetParameterDescription("in", "Input geo-referenced DEM to convert to general raster format.");

    AddParameter(ParameterType_OutputFilename,    "out", "Prefix of the output files");
    std::ostringstream oss;
    oss << "will be used to get the prefix (name withtout extensions) of the files to write. ";
    oss << "Three files - prefix.geom, prefix.omd and prefix.ras - will be generated.";
    SetParameterDescription("out", oss.str());
    //MandatoryOn("out");

    // Doc example parameter settings
    SetDocExampleParameterValue("in", "QB_Toulouse_Ortho_Elev.tif");
    SetDocExampleParameterValue("out", "outputDEM");
}

void DoUpdateParameters()
{
  // nothing to update
}

/* The main is simple : read image using OTB and write it as a tif.
*  Read this tif using OSSIM and convert it as a general raster file
*  (.ras, .geom and . omd)
*/

void DoExecute()
{
  // Load input image
  FloatVectorImageType::Pointer inImage = GetParameterImage("in");

  // Set temporary tif filename (for ossim)
  std::string ofname = GetParameterString("out");
  std::string path   = itksys::SystemTools::GetFilenamePath(ofname);
  std::string fname  = itksys::SystemTools::GetFilenameWithoutExtension(ofname);
  std::string tempFilename = path+"/"+fname+"_DEMConvert.tif";
  std::string tempFilenameGeom = path+"/"+fname+"_DEMConvert.geom";

  // Generate the tif image using OTB while keeping the same  pixel
  // type then the input image
  // Initialize an outputParameter and set its output pixeltype
  OutputImageParameter::Pointer paramOut = OutputImageParameter::New();
  std::ostringstream osswriter;
  osswriter<< "writing temporary tif file";

  // Set the filename of the current output image
  paramOut->SetFileName(tempFilename);
  paramOut->SetValue(inImage);

  // Set the output pixel type
  itk::ImageIOBase::Pointer  imageIO = ImageIOFactory::CreateImageIO( GetParameterString("in").c_str(),
                                                                      ImageIOFactory::ReadMode);
  std::string componentTypeInfo(imageIO->GetComponentTypeInfo().name());
  if( componentTypeInfo == typeid(unsigned char).name())
    {
    paramOut->SetPixelType(ImagePixelType_uint8);
    }
  else if( componentTypeInfo == typeid(unsigned short).name())
    {
    paramOut->SetPixelType(ImagePixelType_uint16);
    }
  else if( componentTypeInfo == typeid(short).name())
    {
    paramOut->SetPixelType(ImagePixelType_int16);
    }
  else if( componentTypeInfo == typeid(unsigned int).name())
    {
    paramOut->SetPixelType(ImagePixelType_uint32);
    }
  else if( componentTypeInfo == typeid(int).name())
    {
    paramOut->SetPixelType(ImagePixelType_int32);
    }
  else if( componentTypeInfo == typeid(float).name())
    {
    paramOut->SetPixelType(ImagePixelType_float);
    }
  else if( componentTypeInfo == typeid(double).name())
    {
    paramOut->SetPixelType(ImagePixelType_double);
    }
  else
    {
    itkExceptionMacro("This application doesn't support image pixel type " << componentTypeInfo);
    }

  // Add the tempfilename to be written
  paramOut->InitializeWriters();
  AddProcess(paramOut->GetWriter(), osswriter.str());
  paramOut->Write();

  // Set the output ras file
  std::string output = path+"/"+fname+".ras";

  DEMConvertAdapter::Pointer DEMConverter = DEMConvertAdapter::New();
  DEMConverter->Convert(tempFilename, output);

  // remove the temprorary tif file
  if( !itksys::SystemTools::RemoveFile(tempFilename.c_str()) )
    {
    itkExceptionMacro("Problem while removing the file " << tempFilename);
    }

  // remove the geom file if any
  if( itksys::SystemTools::FileExists(tempFilenameGeom.c_str())
      && !itksys::SystemTools::RemoveFile(tempFilenameGeom.c_str()))
    {
    itkExceptionMacro("Problem while removing the Geom file " << tempFilenameGeom);
    }
  }

};

} // namespace otb
}
OTB_APPLICATION_EXPORT(otb::Wrapper::DEMConvert)

<commit_msg>COMP: DEMConvert application (small error)<commit_after>/*=========================================================================

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

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

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

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

#include "otbDEMConvertAdapter.h"

#include "itkImageIOFactory.h"

namespace otb
{
namespace Wrapper
{

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

  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(DEMConvert, otb::Application);

private:
  void DoInit()
  {
    SetName("DEMConvert");
    SetDescription("Converts a geo-referenced DEM image into a general raster file compatible with OTB DEM handling.");

    SetDocName("DEM Conversion");
    SetDocLongDescription("In order to be understood by the Orfeo ToolBox and the underlying OSSIM library, a geo-referenced Digital Elevation Model image can be converted into a general raster image, which consists in 3 files with the following extensions: .ras, .geom and .omd. Once converted, you have to place these files in a separate directory, and you can then use this directory to set the \"DEM Directory\" parameter of a DEM based OTB application or filter.");
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(" ");

    AddDocTag(Tags::Manip);

    AddParameter(ParameterType_InputImage,  "in",  "Input geo-referenced DEM");
    SetParameterDescription("in", "Input geo-referenced DEM to convert to general raster format.");

    AddParameter(ParameterType_OutputFilename,    "out", "Prefix of the output files");
    std::ostringstream oss;
    oss << "will be used to get the prefix (name withtout extensions) of the files to write. ";
    oss << "Three files - prefix.geom, prefix.omd and prefix.ras - will be generated.";
    SetParameterDescription("out", oss.str());
    //MandatoryOn("out");

    // Doc example parameter settings
    SetDocExampleParameterValue("in", "QB_Toulouse_Ortho_Elev.tif");
    SetDocExampleParameterValue("out", "outputDEM");
}

void DoUpdateParameters()
{
  // nothing to update
}

/* The main is simple : read image using OTB and write it as a tif.
*  Read this tif using OSSIM and convert it as a general raster file
*  (.ras, .geom and . omd)
*/

void DoExecute()
{
  // Load input image
  FloatVectorImageType::Pointer inImage = GetParameterImage("in");

  // Set temporary tif filename (for ossim)
  std::string ofname = GetParameterString("out");
  std::string path   = itksys::SystemTools::GetFilenamePath(ofname);
  std::string fname  = itksys::SystemTools::GetFilenameWithoutExtension(ofname);
  std::string tempFilename = path+"/"+fname+"_DEMConvert.tif";
  std::string tempFilenameGeom = path+"/"+fname+"_DEMConvert.geom";

  // Generate the tif image using OTB while keeping the same  pixel
  // type then the input image
  // Initialize an outputParameter and set its output pixeltype
  OutputImageParameter::Pointer paramOut = OutputImageParameter::New();
  std::ostringstream osswriter;
  osswriter<< "writing temporary tif file";

  // Set the filename of the current output image
  paramOut->SetFileName(tempFilename);
  paramOut->SetValue(inImage);

  // Set the output pixel type
  ImageIOBase::Pointer  imageIO = ImageIOFactory::CreateImageIO( GetParameterString("in").c_str(),
                                                                      ImageIOFactory::ReadMode);
  std::string componentTypeInfo(imageIO->GetComponentTypeInfo().name());
  if( componentTypeInfo == typeid(unsigned char).name())
    {
    paramOut->SetPixelType(ImagePixelType_uint8);
    }
  else if( componentTypeInfo == typeid(unsigned short).name())
    {
    paramOut->SetPixelType(ImagePixelType_uint16);
    }
  else if( componentTypeInfo == typeid(short).name())
    {
    paramOut->SetPixelType(ImagePixelType_int16);
    }
  else if( componentTypeInfo == typeid(unsigned int).name())
    {
    paramOut->SetPixelType(ImagePixelType_uint32);
    }
  else if( componentTypeInfo == typeid(int).name())
    {
    paramOut->SetPixelType(ImagePixelType_int32);
    }
  else if( componentTypeInfo == typeid(float).name())
    {
    paramOut->SetPixelType(ImagePixelType_float);
    }
  else if( componentTypeInfo == typeid(double).name())
    {
    paramOut->SetPixelType(ImagePixelType_double);
    }
  else
    {
    itkExceptionMacro("This application doesn't support image pixel type " << componentTypeInfo);
    }

  // Add the tempfilename to be written
  paramOut->InitializeWriters();
  AddProcess(paramOut->GetWriter(), osswriter.str());
  paramOut->Write();

  // Set the output ras file
  std::string output = path+"/"+fname+".ras";

  DEMConvertAdapter::Pointer DEMConverter = DEMConvertAdapter::New();
  DEMConverter->Convert(tempFilename, output);

  // remove the temprorary tif file
  if( !itksys::SystemTools::RemoveFile(tempFilename.c_str()) )
    {
    itkExceptionMacro("Problem while removing the file " << tempFilename);
    }

  // remove the geom file if any
  if( itksys::SystemTools::FileExists(tempFilenameGeom.c_str())
      && !itksys::SystemTools::RemoveFile(tempFilenameGeom.c_str()))
    {
    itkExceptionMacro("Problem while removing the Geom file " << tempFilenameGeom);
    }
  }

};

} // namespace otb
}
OTB_APPLICATION_EXPORT(otb::Wrapper::DEMConvert)

<|endoftext|>