<commit_before>//
// This file is part of khmer, http://github.com/ged-lab/khmer/, and is
// Copyright (C) Michigan State University, 2009-2013. It is licensed under
// the three-clause BSD license; see doc/LICENSE.txt.
// Contact: <EMAIL>
//

#include "read_parsers.hh"

#include <cstring>
#include "khmer_exception.hh"
#include <seqan/sequence.h>
#include <seqan/seq_io.h>
#include <seqan/stream.h>
#include <pthread.h>

namespace khmer
{


namespace read_parsers
{

struct SeqAnParser::Handle {
    seqan::SequenceStream stream;
    uint32_t seqan_spin_lock;
};

SeqAnParser::SeqAnParser( char const * filename ) : IParser( )
{
    _private = new SeqAnParser::Handle();
    seqan::open(_private->stream, filename);
    if (!seqan::isGood(_private->stream)) {
        std::string message = "Could not open ";
        message = message + filename + " for reading.";
        throw InvalidStreamHandle(message.c_str());
    } else if (seqan::atEnd(_private->stream)) {
        std::string message = "File ";
        message = message + filename + " does not contain any sequences!";
        throw InvalidStreamHandle(message.c_str());
    }
    __asm__ __volatile__ ("" ::: "memory");
    _private->seqan_spin_lock = 0;
}

bool SeqAnParser::is_complete()
{
    return !seqan::isGood(_private->stream) || seqan::atEnd(_private->stream);
}

void SeqAnParser::imprint_next_read(Read &the_read)
{
    the_read.reset();
    int ret = -1;
    while (!__sync_bool_compare_and_swap(& _private->seqan_spin_lock, 0, 1));
    bool atEnd = seqan::atEnd(_private->stream);
    if (!atEnd) {
        ret = seqan::readRecord(the_read.name, the_read.sequence,
                                the_read.quality, _private->stream);
        if (ret == 0) {
            _num_reads++;
        }
    }
    __asm__ __volatile__ ("" ::: "memory");
    _private->seqan_spin_lock = 0;
    if (!atEnd) {
        if (_num_reads > 0 && the_read.quality.length() != 0) {
            _have_qualities = true;
        }
        if (the_read.sequence.length() == 0) {
            // We decrement the number of reads we've got, as the last one is
            // invlaid
            __sync_fetch_and_sub(&_num_reads, 1);
            throw InvalidRead("Sequence is empty");
        }
        if (_have_qualities) {
            if (the_read.sequence.length() != the_read.quality.length()) {
                // We decrement the number of reads we've got, as the last one
                // is invlaid
                __sync_fetch_and_sub(&_num_reads, 1);
                throw InvalidRead("Sequence and quality lengths differ");
            }
        }
    } else {
        throw NoMoreReadsAvailable();
    }
    if (ret != 0) {
        // No need to decrement _num_reads, as we didn't increment it above
        throw StreamReadError();
    }
}

SeqAnParser::~SeqAnParser()
{
    seqan::close(_private->stream);
    delete _private;
}

IParser * const
IParser::
get_parser(
    std:: string const	    &ifile_name
)
{
<commit_msg>Move threaded stuff into spinlock, throws outside<commit_after>//
// This file is part of khmer, http://github.com/ged-lab/khmer/, and is
// Copyright (C) Michigan State University, 2009-2013. It is licensed under
// the three-clause BSD license; see doc/LICENSE.txt.
// Contact: <EMAIL>
//

#include "read_parsers.hh"

#include <cstring>
#include "khmer_exception.hh"
#include <seqan/sequence.h>
#include <seqan/seq_io.h>
#include <seqan/stream.h>
#include <pthread.h>

namespace khmer
{


namespace read_parsers
{

struct SeqAnParser::Handle {
    seqan::SequenceStream stream;
    uint32_t seqan_spin_lock;
};

SeqAnParser::SeqAnParser( char const * filename ) : IParser( )
{
    _private = new SeqAnParser::Handle();
    seqan::open(_private->stream, filename);
    if (!seqan::isGood(_private->stream)) {
        std::string message = "Could not open ";
        message = message + filename + " for reading.";
        throw InvalidStreamHandle(message.c_str());
    } else if (seqan::atEnd(_private->stream)) {
        std::string message = "File ";
        message = message + filename + " does not contain any sequences!";
        throw InvalidStreamHandle(message.c_str());
    }
    __asm__ __volatile__ ("" ::: "memory");
    _private->seqan_spin_lock = 0;
}

bool SeqAnParser::is_complete()
{
    return !seqan::isGood(_private->stream) || seqan::atEnd(_private->stream);
}

void SeqAnParser::imprint_next_read(Read &the_read)
{
    the_read.reset();
    int ret = -1;
    const char *invalid_read_exc = NULL;
    while (!__sync_bool_compare_and_swap(& _private->seqan_spin_lock, 0, 1));
    bool atEnd = seqan::atEnd(_private->stream);
    if (!atEnd) {
        ret = seqan::readRecord(the_read.name, the_read.sequence,
                                the_read.quality, _private->stream);
        if (ret == 0) {
            // Detect if we're parsing something w/ qualities on the first read
            // only
            if (_num_reads == 0 && the_read.quality.length() != 0) {
                _have_qualities = true;
            }

            // Handle error cases, or increment number of reads on success
            if (the_read.sequence.length() == 0) {
                invalid_read_exc = "Sequence is empty";
            } else if (_have_qualities && (the_read.sequence.length() != \
                                           the_read.quality.length())) {
                invalid_read_exc = "Sequence and quality lengths differ";
            } else {
                _num_reads++;
            }
        }
    }
    __asm__ __volatile__ ("" ::: "memory");
    _private->seqan_spin_lock = 0;
    // Throw any error in the read, even if we're at the end
    if (invalid_read_exc != NULL) {
        throw InvalidRead(invalid_read_exc);
    }
    // Throw NoMoreReadsAvailable if none of the above errors were raised, even
    // if ret == 0
    if (atEnd) {
        throw NoMoreReadsAvailable();
    }
    // Catch-all error in readRecord that isn't one of the above
    if (ret != 0) {
        throw StreamReadError();
    }
}

SeqAnParser::~SeqAnParser()
{
    seqan::close(_private->stream);
    delete _private;
}

IParser * const
IParser::
get_parser(
    std:: string const	    &ifile_name
)
{

{'fraction_non_alphanumeric': 0.12884522467386053, 'fraction_numerical': 0.006925430826220004, 'mean_word_length': 2.566915565766801, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3055899', 'n_tokens_mistral': 2004, 'n_tokens_neox': 1926, 'n_words': 476}