<commit_before>#include "block_sync.h"

namespace redsea {

namespace {

const unsigned kBitmask16 = 0x000FFFF;
const unsigned kBitmask26 = 0x3FFFFFF;
const unsigned kBitmask28 = 0xFFFFFFF;

const unsigned kMaxErrorLength = 5;

const std::vector<uint16_t> offset_words =
  {0x0FC, 0x198, 0x168, 0x350, 0x1B4};
const std::map<uint16_t,eOffset> offset_syndromes =
  {{0x3D8,OFFSET_A},  {0x3D4,OFFSET_B}, {0x25C,OFFSET_C},
   {0x3CC,OFFSET_CI}, {0x258,OFFSET_D}};
const std::vector<uint16_t> block_number_for_offset =
  {0, 1, 2, 2, 3};

// Section B.1.1: '-- calculated by the modulo-two addition of all the rows of
// the -- matrix for which the corresponding coefficient in the -- vector is 1.'
uint32_t matrixMultiply(uint32_t vec, const std::vector<uint32_t>& matrix) {

  uint32_t result = 0;

  for (int k=0; k<(int)matrix.size(); k++)
    if ((vec >> k) & 0x01)
      result ^= matrix[matrix.size() - 1 - k];

  return result;
}

// Section B.2.1: 'The calculation of the syndromes -- can easily be done by
// multiplying each word with the parity matrix H.'
uint32_t calcSyndrome(uint32_t vec) {

  static const std::vector<uint32_t> parity_check_matrix({
      0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004,
      0x002, 0x001, 0x2dc, 0x16e, 0x0b7, 0x287, 0x39f, 0x313,
      0x355, 0x376, 0x1bb, 0x201, 0x3dc,
      0x1ee, 0x0f7, 0x2a7, 0x38f, 0x31b
  });

  return matrixMultiply(vec, parity_check_matrix);
}

eOffset nextOffsetFor(eOffset o) {
  static const std::map<eOffset,eOffset> next_offset({
      {OFFSET_A,OFFSET_B}, {OFFSET_B,OFFSET_C},
      {OFFSET_C,OFFSET_D}, {OFFSET_CI,OFFSET_D},
      {OFFSET_D,OFFSET_A}
  });
  return next_offset.at(o);
}

// Precompute mapping of syndromes to error vectors
std::map<uint16_t,uint32_t> makeErrorLookupTable() {

  std::map<uint16_t,uint32_t> result;

  for (uint32_t e=1; e < (1<<kMaxErrorLength); e++) {
    for (unsigned shift=0; shift < 26; shift++) {
      uint32_t errvec = ((e << shift) & kBitmask26);

      uint32_t sy = calcSyndrome(errvec);
      result[sy] = errvec;
    }
  }
  return result;
}

} // namespace

BlockStream::BlockStream(eInputType input_type) : bitcount_(0),
  prevbitcount_(0), left_to_read_(0), wideblock_(0), prevsync_(0),
  block_counter_(0), expected_offset_(OFFSET_A),
  received_offset_(OFFSET_INVALID), pi_(0), is_in_sync_(false), group_data_(4),
  has_block_(5), block_has_errors_(50), subcarrier_(), ascii_bits_(),
  error_lookup_(makeErrorLookupTable()), num_blocks_received_(0),
  input_type_(input_type), is_eof_(false) {

}

int BlockStream::getNextBit() {
  int result = 0;
  if (input_type_ == INPUT_MPX) {
    result = subcarrier_.getNextBit();
    is_eof_ = subcarrier_.isEOF();

  } else if (input_type_ == INPUT_ASCIIBITS) {
    result = ascii_bits_.getNextBit();
    is_eof_ = ascii_bits_.isEOF();
  }

  return result;
}

// Section B.2.2
uint32_t BlockStream::correctBurstErrors(uint32_t block) const {

  uint16_t synd_reg =
    calcSyndrome(block ^ offset_words[expected_offset_]);

  uint32_t corrected_block = block;

  if (error_lookup_.find(synd_reg) != error_lookup_.end()) {
    corrected_block = (block ^ offset_words[expected_offset_])
      ^ (error_lookup_.at(synd_reg));
  }

  return corrected_block;

}

// When a block can't be decoded, save the beginning of the group if possible
void BlockStream::uncorrectable() {
  num_blocks_received_ = 0;

  for (eOffset o : {OFFSET_A, OFFSET_B, OFFSET_C, OFFSET_CI}) {
    if (has_block_[o]) {
      num_blocks_received_ = block_number_for_offset[o] + 1;
    } else {
      break;
    }
  }

  block_has_errors_[block_counter_ % block_has_errors_.size()] = true;

  unsigned num_erroneous_blocks = 0;
  for (bool e : block_has_errors_) {
    if (e)
      num_erroneous_blocks ++;
  }

  // Sync is lost when >45 out of last 50 blocks are erroneous (Section C.1.2)
  if (is_in_sync_ && num_erroneous_blocks > 45) {
    is_in_sync_ = false;
    for (unsigned i=0; i<block_has_errors_.size(); i++)
      block_has_errors_[i] = false;
    pi_ = 0x0000;
  }

  for (eOffset o : {OFFSET_A, OFFSET_B, OFFSET_C, OFFSET_CI, OFFSET_D})
    has_block_[o] = false;

}

bool BlockStream::acquireSync() {

  if (is_in_sync_)
    return true;

  // Try to find the repeating offset sequence
  if (received_offset_ != OFFSET_INVALID) {
    int dist = bitcount_ - prevbitcount_;

    if (dist % 26 == 0 && dist <= 156 &&
        (block_number_for_offset[prevsync_] + dist/26) % 4 ==
        block_number_for_offset[received_offset_]) {
      is_in_sync_ = true;
      expected_offset_ = received_offset_;
      //printf(":sync!\n");
    } else {
      prevbitcount_ = bitcount_;
      prevsync_ = received_offset_;
    }
  }

  return is_in_sync_;

}

Group BlockStream::getNextGroup() {

  num_blocks_received_ = 0;

  while (num_blocks_received_ == 0 && !isEOF()) {

    // Compensate for clock slip corrections
    bitcount_ += 26 - left_to_read_;

    // Read from radio
    for (int i=0; i < (is_in_sync_ ? (int)left_to_read_ : 1); i++,bitcount_++) {
      wideblock_ = (wideblock_ << 1) + getNextBit();
    }

    left_to_read_ = 26;
    wideblock_ &= kBitmask28;

    uint32_t block = (wideblock_ >> 1) & kBitmask26;

    uint16_t syndrome = calcSyndrome(block);
    received_offset_ = (offset_syndromes.count(syndrome) > 0 ?
        offset_syndromes.at(syndrome) : OFFSET_INVALID);

    if (!acquireSync())
      continue;

    block_counter_ ++;
    uint16_t message = block >> 10;

    if (expected_offset_ == OFFSET_C && received_offset_ == OFFSET_CI)
      expected_offset_ = OFFSET_CI;

    if ( received_offset_ != expected_offset_) {

      // If message is a correct PI, error was probably in check bits
      if (expected_offset_ == OFFSET_A && message == pi_ && pi_ != 0) {
        received_offset_ = OFFSET_A;
        //printf(":offset 0: ignoring error in check bits\n");
      } else if (expected_offset_ == OFFSET_C && message == pi_ && pi_ != 0) {
        received_offset_ = OFFSET_CI;
        //printf(":offset 0: ignoring error in check bits\n");

      // Detect & correct clock slips (Section C.1.2)
      } else if (expected_offset_ == OFFSET_A && pi_ != 0 &&
          ((wideblock_ >> 12) & kBitmask16) == pi_) {
        message = pi_;
        wideblock_ >>= 1;
        received_offset_ = OFFSET_A;
        //printf(":offset 0: clock slip corrected\n");
      } else if (expected_offset_ == OFFSET_A && pi_ != 0 &&
          ((wideblock_ >> 10) & kBitmask16) == pi_) {
        message = pi_;
        wideblock_ = (wideblock_ << 1) + getNextBit();
        received_offset_ = OFFSET_A;
        left_to_read_ = 25;
        //printf(":offset 0: clock slip corrected\n");

      } else {

        block = correctBurstErrors(block);
        if (calcSyndrome(block) == 0x000) {
          message = block >> 10;
          received_offset_ = expected_offset_;
        }

      }

      // Still no valid syndrome
      if (received_offset_ != expected_offset_)
        uncorrectable();
    }

    // Error-free block received

    if (received_offset_ == expected_offset_) {

      group_data_[block_number_for_offset[expected_offset_]] = message;
      has_block_[expected_offset_] = true;

      if (expected_offset_ == OFFSET_A) {
        pi_ = message;
      }

      // Complete group received
      if (has_block_[OFFSET_A] && has_block_[OFFSET_B] &&
         (has_block_[OFFSET_C] || has_block_[OFFSET_CI]) &&
          has_block_[OFFSET_D]) {
        num_blocks_received_ = 4;
      }
    }

    expected_offset_ = nextOffsetFor(expected_offset_);

    // End-of-group reset
    if (expected_offset_ == OFFSET_A) {
      for (eOffset o : {OFFSET_A, OFFSET_B, OFFSET_C, OFFSET_CI, OFFSET_D})
        has_block_[o] = false;
    }

  }

  std::vector<uint16_t> result = group_data_;
  result.resize(num_blocks_received_);

  return Group(result);

}

bool BlockStream::isEOF() const {
  return is_eof_;
}

#ifdef DEBUG
float BlockStream::getT() const {
  return subcarrier_.getT();
}
#endif

} // namespace redsea
<commit_msg>only accept valid PI<commit_after>#include "block_sync.h"

namespace redsea {

namespace {

const unsigned kBitmask16 = 0x000FFFF;
const unsigned kBitmask26 = 0x3FFFFFF;
const unsigned kBitmask28 = 0xFFFFFFF;

const unsigned kMaxErrorLength = 5;

const std::vector<uint16_t> offset_words =
  {0x0FC, 0x198, 0x168, 0x350, 0x1B4};
const std::map<uint16_t,eOffset> offset_syndromes =
  {{0x3D8,OFFSET_A},  {0x3D4,OFFSET_B}, {0x25C,OFFSET_C},
   {0x3CC,OFFSET_CI}, {0x258,OFFSET_D}};
const std::vector<uint16_t> block_number_for_offset =
  {0, 1, 2, 2, 3};

// Section B.1.1: '-- calculated by the modulo-two addition of all the rows of
// the -- matrix for which the corresponding coefficient in the -- vector is 1.'
uint32_t matrixMultiply(uint32_t vec, const std::vector<uint32_t>& matrix) {

  uint32_t result = 0;

  for (int k=0; k<(int)matrix.size(); k++)
    if ((vec >> k) & 0x01)
      result ^= matrix[matrix.size() - 1 - k];

  return result;
}

// Section B.2.1: 'The calculation of the syndromes -- can easily be done by
// multiplying each word with the parity matrix H.'
uint32_t calcSyndrome(uint32_t vec) {

  static const std::vector<uint32_t> parity_check_matrix({
      0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004,
      0x002, 0x001, 0x2dc, 0x16e, 0x0b7, 0x287, 0x39f, 0x313,
      0x355, 0x376, 0x1bb, 0x201, 0x3dc,
      0x1ee, 0x0f7, 0x2a7, 0x38f, 0x31b
  });

  return matrixMultiply(vec, parity_check_matrix);
}

eOffset nextOffsetFor(eOffset o) {
  static const std::map<eOffset,eOffset> next_offset({
      {OFFSET_A,OFFSET_B}, {OFFSET_B,OFFSET_C},
      {OFFSET_C,OFFSET_D}, {OFFSET_CI,OFFSET_D},
      {OFFSET_D,OFFSET_A}
  });
  return next_offset.at(o);
}

// Precompute mapping of syndromes to error vectors
std::map<uint16_t,uint32_t> makeErrorLookupTable() {

  std::map<uint16_t,uint32_t> result;

  for (uint32_t e=1; e < (1<<kMaxErrorLength); e++) {
    for (unsigned shift=0; shift < 26; shift++) {
      uint32_t errvec = ((e << shift) & kBitmask26);

      uint32_t sy = calcSyndrome(errvec);
      result[sy] = errvec;
    }
  }
  return result;
}

} // namespace

BlockStream::BlockStream(eInputType input_type) : bitcount_(0),
  prevbitcount_(0), left_to_read_(0), wideblock_(0), prevsync_(0),
  block_counter_(0), expected_offset_(OFFSET_A),
  received_offset_(OFFSET_INVALID), pi_(0), is_in_sync_(false), group_data_(4),
  has_block_(5), block_has_errors_(50), subcarrier_(), ascii_bits_(),
  error_lookup_(makeErrorLookupTable()), num_blocks_received_(0),
  input_type_(input_type), is_eof_(false) {

}

int BlockStream::getNextBit() {
  int result = 0;
  if (input_type_ == INPUT_MPX) {
    result = subcarrier_.getNextBit();
    is_eof_ = subcarrier_.isEOF();

  } else if (input_type_ == INPUT_ASCIIBITS) {
    result = ascii_bits_.getNextBit();
    is_eof_ = ascii_bits_.isEOF();
  }

  return result;
}

// Section B.2.2
uint32_t BlockStream::correctBurstErrors(uint32_t block) const {

  uint16_t synd_reg =
    calcSyndrome(block ^ offset_words[expected_offset_]);

  uint32_t corrected_block = block;

  if (error_lookup_.find(synd_reg) != error_lookup_.end()) {
    corrected_block = (block ^ offset_words[expected_offset_])
      ^ (error_lookup_.at(synd_reg));
  }

  return corrected_block;

}

// When a block can't be decoded, save the beginning of the group if possible
void BlockStream::uncorrectable() {
  num_blocks_received_ = 0;

  for (eOffset o : {OFFSET_A, OFFSET_B, OFFSET_C, OFFSET_CI}) {
    if (has_block_[o]) {
      num_blocks_received_ = block_number_for_offset[o] + 1;
    } else {
      break;
    }
  }

  block_has_errors_[block_counter_ % block_has_errors_.size()] = true;

  unsigned num_erroneous_blocks = 0;
  for (bool e : block_has_errors_) {
    if (e)
      num_erroneous_blocks ++;
  }

  // Sync is lost when >45 out of last 50 blocks are erroneous (Section C.1.2)
  if (is_in_sync_ && num_erroneous_blocks > 45) {
    is_in_sync_ = false;
    for (unsigned i=0; i<block_has_errors_.size(); i++)
      block_has_errors_[i] = false;
    pi_ = 0x0000;
  }

  for (eOffset o : {OFFSET_A, OFFSET_B, OFFSET_C, OFFSET_CI, OFFSET_D})
    has_block_[o] = false;

}

bool BlockStream::acquireSync() {

  if (is_in_sync_)
    return true;

  // Try to find the repeating offset sequence
  if (received_offset_ != OFFSET_INVALID) {
    int dist = bitcount_ - prevbitcount_;

    if (dist % 26 == 0 && dist <= 156 &&
        (block_number_for_offset[prevsync_] + dist/26) % 4 ==
        block_number_for_offset[received_offset_]) {
      is_in_sync_ = true;
      expected_offset_ = received_offset_;
      //printf(":sync!\n");
    } else {
      prevbitcount_ = bitcount_;
      prevsync_ = received_offset_;
    }
  }

  return is_in_sync_;

}

Group BlockStream::getNextGroup() {

  num_blocks_received_ = 0;

  while (num_blocks_received_ == 0 && !isEOF()) {

    // Compensate for clock slip corrections
    bitcount_ += 26 - left_to_read_;

    // Read from radio
    for (int i=0; i < (is_in_sync_ ? (int)left_to_read_ : 1); i++,bitcount_++) {
      wideblock_ = (wideblock_ << 1) + getNextBit();
    }

    left_to_read_ = 26;
    wideblock_ &= kBitmask28;

    uint32_t block = (wideblock_ >> 1) & kBitmask26;

    uint16_t syndrome = calcSyndrome(block);
    received_offset_ = (offset_syndromes.count(syndrome) > 0 ?
        offset_syndromes.at(syndrome) : OFFSET_INVALID);

    if (!acquireSync())
      continue;

    block_counter_ ++;
    uint16_t message = block >> 10;
    bool was_valid_word = true;

    if (expected_offset_ == OFFSET_C && received_offset_ == OFFSET_CI)
      expected_offset_ = OFFSET_CI;

    if ( received_offset_ != expected_offset_) {

      was_valid_word = false;

      // If message is a correct PI, error was probably in check bits
      if (expected_offset_ == OFFSET_A && message == pi_ && pi_ != 0) {
        received_offset_ = OFFSET_A;
        //printf(":offset 0: ignoring error in check bits\n");
      } else if (expected_offset_ == OFFSET_C && message == pi_ && pi_ != 0) {
        received_offset_ = OFFSET_CI;
        //printf(":offset 0: ignoring error in check bits\n");

      // Detect & correct clock slips (Section C.1.2)
      } else if (expected_offset_ == OFFSET_A && pi_ != 0 &&
          ((wideblock_ >> 12) & kBitmask16) == pi_) {
        message = pi_;
        wideblock_ >>= 1;
        received_offset_ = OFFSET_A;
        //printf(":offset 0: clock slip corrected\n");
      } else if (expected_offset_ == OFFSET_A && pi_ != 0 &&
          ((wideblock_ >> 10) & kBitmask16) == pi_) {
        message = pi_;
        wideblock_ = (wideblock_ << 1) + getNextBit();
        received_offset_ = OFFSET_A;
        left_to_read_ = 25;
        //printf(":offset 0: clock slip corrected\n");

      } else {

        block = correctBurstErrors(block);
        if (calcSyndrome(block) == 0x000) {
          message = block >> 10;
          received_offset_ = expected_offset_;
        }

      }

      // Still no valid syndrome
      if (received_offset_ != expected_offset_)
        uncorrectable();
    }

    // Error-free block received

    if (received_offset_ == expected_offset_) {

      group_data_[block_number_for_offset[expected_offset_]] = message;
      has_block_[expected_offset_] = true;

      if (expected_offset_ == OFFSET_A && was_valid_word) {
        pi_ = message;
      }

      // Complete group received
      if (has_block_[OFFSET_A] && has_block_[OFFSET_B] &&
         (has_block_[OFFSET_C] || has_block_[OFFSET_CI]) &&
          has_block_[OFFSET_D]) {
        num_blocks_received_ = 4;
      }
    }

    expected_offset_ = nextOffsetFor(expected_offset_);

    // End-of-group reset
    if (expected_offset_ == OFFSET_A) {
      for (eOffset o : {OFFSET_A, OFFSET_B, OFFSET_C, OFFSET_CI, OFFSET_D})
        has_block_[o] = false;
    }

  }

  std::vector<uint16_t> result = group_data_;
  result.resize(num_blocks_received_);

  return Group(result);

}

bool BlockStream::isEOF() const {
  return is_eof_;
}

#ifdef DEBUG
float BlockStream::getT() const {
  return subcarrier_.getT();
}
#endif

} // namespace redsea
<|endoftext|>


<commit_before>/*
 * Copyright 2008 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

/*
 * Implementation of the burstsort algorithm by Sinha, Zobel et al.
 *
 * @article{1041517,
 *     author = {Ranjan Sinha and Justin Zobel},
 *     title = {Cache-conscious sorting of large sets of strings with dynamic tries},
 *     journal = {J. Exp. Algorithmics},
 *     volume = {9},
 *     year = {2004},
 *     issn = {1084-6654},
 *     pages = {1.5},
 *     doi = {http://doi.acm.org/10.1145/1005813.1041517},
 *     publisher = {ACM},
 *     address = {New York, NY, USA},
 * }
 */

#include "util/get_char.h"
#include <vector>
#include <iostream>
#include <bitset>
#include "vector_bagwell.h"
#include "vector_brodnik.h"
#include "vector_block.h"
#include <boost/array.hpp>

using boost::array;

// Unfortunately std::numeric_limits<T>::max() cannot be used as constant
// values in template parameters.
template <typename T> struct max {};
template <> struct max<unsigned char> { enum { value = 0x100   }; };
template <> struct max<uint16_t>      { enum { value = 0x10000 }; };

template <typename CharT>
struct TrieNode
{
	// One subtree per alphabet. Points to either a 'TrieNode' or a
	// 'Bucket' node. Use the value from is_trie to know which one.
	array<void*, max<CharT>::value> buckets;
	// is_trie[i] equals true if buckets[i] points to a TrieNode
	// is_trie[i] equals false if buckets[i] points to a Bucket
	std::bitset<max<CharT>::value>  is_trie;
	TrieNode() { buckets.assign(0); }
};

// The burst algorithm as described by Sinha, Zobel et al.
template <typename CharT>
struct BurstSimple
{
	template <typename BucketT>
	TrieNode<CharT>*
	operator()(const BucketT& bucket, size_t depth) const
	{
		TrieNode<CharT>* new_node = new TrieNode<CharT>;
		const unsigned bucket_size = bucket.size();
		// Use a small cache to reduce memory stalls. Also cache the
		// string pointers, in case the indexing operation of the
		// container is expensive.
		unsigned i=0;
		for (; i < bucket_size-bucket_size%64; i+=64) {
			array<CharT, 64> cache;
			array<unsigned char*, 64> strings;
			for (unsigned j=0; j < 64; ++j) {
				strings[j] = bucket[i+j];
				cache[j] = get_char<CharT>(strings[j], depth);
			}
			for (unsigned j=0; j < 64; ++j) {
				const CharT ch = cache[j];
				BucketT* sub_bucket = static_cast<BucketT*>(
					new_node->buckets[ch]);
				if (not sub_bucket) {
					new_node->buckets[ch] = sub_bucket
						= new BucketT;
				}
				sub_bucket->push_back(strings[j]);
			}
		}
		for (; i < bucket_size; ++i) {
			unsigned char* ptr = bucket[i];
			const CharT ch = get_char<CharT>(ptr, depth);
			BucketT* sub_bucket = static_cast<BucketT*>(
				new_node->buckets[ch]);
			if (not sub_bucket) {
				new_node->buckets[ch] = sub_bucket
					= new BucketT;
			}
			sub_bucket->push_back(ptr);
		}
		return new_node;
	}
};

// Another burst variant: After bursting the bucket, immediately burst large
// sub buckets in a recursive fashion.
template <typename CharT>
struct BurstRecursive
{
	template <typename BucketT>
	TrieNode<CharT>*
	operator()(const BucketT& bucket, size_t depth) const
	{
		TrieNode<CharT>* new_node
			= BurstSimple<CharT>()(bucket, depth);
		const size_t threshold = std::max(
				//size_t(100), size_t(0.4f*bucket.size()));
				size_t(100), bucket.size()/2);
		for (unsigned i=0; i < max<CharT>::value; ++i) {
			assert(new_node->is_trie[i] == false);
			BucketT* sub_bucket = static_cast<BucketT*>(
					new_node->buckets[i]);
			if (not sub_bucket) continue;
			if (not is_end(i) and sub_bucket->size() > threshold) {
				new_node->buckets[i] =
					BurstRecursive<CharT>()(*sub_bucket,
							depth+sizeof(CharT));
				delete sub_bucket;
				new_node->is_trie[i] = true;
			}
		}
		return new_node;
	}
};

template <unsigned Threshold, typename BucketT,
          typename BurstImpl, typename CharT>
static inline void
insert(TrieNode<CharT>* root, unsigned char** strings, size_t n)
{
	for (size_t i=0; i < n; ++i) {
		unsigned char* str = strings[i];
		size_t depth = 0;
		CharT c = get_char<CharT>(str, 0);
		TrieNode<CharT>* node = root;
		while (node->is_trie[c]) {
			assert(not is_end(c));
			node = static_cast<TrieNode<CharT>*>(node->buckets[c]);
			depth += sizeof(CharT);
			c = get_char<CharT>(str, depth);
		}
		BucketT* bucket = static_cast<BucketT*>(node->buckets[c]);
		if (not bucket) {
			node->buckets[c] = bucket = new BucketT;
		}
		bucket->push_back(str);
		if (is_end(c)) continue;
		if (bucket->size() > Threshold) {
			node->buckets[c] = BurstImpl()(*bucket,
					depth+sizeof(CharT));
			node->is_trie[c] = true;
			delete bucket;
		}
	}
}

// Use a wrapper to std::copy(). I haven't implemented iterators for some of my
// containers, instead they have optimized copy(bucket, dst).
static inline void
copy(const std::vector<unsigned char*>& bucket, unsigned char** dst)
{
	std::copy(bucket.begin(), bucket.end(), dst);
}

// Traverses the trie and copies the strings back to the original string array.
// Nodes and buckets are deleted from memory during the traversal. The root
// node given to this function will also be deleted.
template <typename BucketT, typename SmallSort, typename CharT>
static unsigned char**
traverse(TrieNode<CharT>* node,
         unsigned char** dst,
         size_t depth,
         SmallSort small_sort)
{
	for (unsigned i=0; i < max<CharT>::value; ++i) {
		if (node->is_trie[i]) {
			dst = traverse<BucketT>(
				static_cast<TrieNode<CharT>*>(node->buckets[i]),
				dst, depth+sizeof(CharT), small_sort);
		} else {
			BucketT* bucket =
				static_cast<BucketT*>(node->buckets[i]);
			if (not bucket) continue;
			size_t bsize = bucket->size();
			copy(*bucket, dst);
			if (not is_end(i)) small_sort(dst, bsize, depth);
			dst += bsize;
			delete bucket;
		}
	}
	delete node;
	return dst;
}

//#define SmallSort mkqsort
#define SmallSort msd_CE2
void msd_CE2(unsigned char**, size_t, size_t);

void burstsort_vector(unsigned char** strings, size_t n)
{
	typedef unsigned char CharT;
	typedef std::vector<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<8000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_brodnik(unsigned char** strings, size_t n)
{
	typedef unsigned char CharT;
	typedef vector_brodnik<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<16000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_bagwell(unsigned char** strings, size_t n)
{
	typedef unsigned char CharT;
	typedef vector_bagwell<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<16000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_vector_block(unsigned char** strings, size_t n)
{
	typedef unsigned char CharT;
	typedef vector_block<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<16000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_superalphabet_vector(unsigned char** strings, size_t n)
{
	typedef uint16_t CharT;
	typedef std::vector<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<32000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_superalphabet_brodnik(unsigned char** strings, size_t n)
{
	typedef uint16_t CharT;
	typedef vector_brodnik<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<32000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_superalphabet_bagwell(unsigned char** strings, size_t n)
{
	typedef uint16_t CharT;
	typedef vector_bagwell<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<32000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_superalphabet_vector_block(unsigned char** strings, size_t n)
{
	typedef uint16_t CharT;
	typedef vector_block<unsigned char*, 128> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<32000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}
<commit_msg>use mkqsort() as SmallSort<commit_after>/*
 * Copyright 2008 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

/*
 * Implementation of the burstsort algorithm by Sinha, Zobel et al.
 *
 * @article{1041517,
 *     author = {Ranjan Sinha and Justin Zobel},
 *     title = {Cache-conscious sorting of large sets of strings with dynamic tries},
 *     journal = {J. Exp. Algorithmics},
 *     volume = {9},
 *     year = {2004},
 *     issn = {1084-6654},
 *     pages = {1.5},
 *     doi = {http://doi.acm.org/10.1145/1005813.1041517},
 *     publisher = {ACM},
 *     address = {New York, NY, USA},
 * }
 */

#include "util/get_char.h"
#include <vector>
#include <iostream>
#include <bitset>
#include "vector_bagwell.h"
#include "vector_brodnik.h"
#include "vector_block.h"
#include <boost/array.hpp>

using boost::array;

// Unfortunately std::numeric_limits<T>::max() cannot be used as constant
// values in template parameters.
template <typename T> struct max {};
template <> struct max<unsigned char> { enum { value = 0x100   }; };
template <> struct max<uint16_t>      { enum { value = 0x10000 }; };

template <typename CharT>
struct TrieNode
{
	// One subtree per alphabet. Points to either a 'TrieNode' or a
	// 'Bucket' node. Use the value from is_trie to know which one.
	array<void*, max<CharT>::value> buckets;
	// is_trie[i] equals true if buckets[i] points to a TrieNode
	// is_trie[i] equals false if buckets[i] points to a Bucket
	std::bitset<max<CharT>::value>  is_trie;
	TrieNode() { buckets.assign(0); }
};

// The burst algorithm as described by Sinha, Zobel et al.
template <typename CharT>
struct BurstSimple
{
	template <typename BucketT>
	TrieNode<CharT>*
	operator()(const BucketT& bucket, size_t depth) const
	{
		TrieNode<CharT>* new_node = new TrieNode<CharT>;
		const unsigned bucket_size = bucket.size();
		// Use a small cache to reduce memory stalls. Also cache the
		// string pointers, in case the indexing operation of the
		// container is expensive.
		unsigned i=0;
		for (; i < bucket_size-bucket_size%64; i+=64) {
			array<CharT, 64> cache;
			array<unsigned char*, 64> strings;
			for (unsigned j=0; j < 64; ++j) {
				strings[j] = bucket[i+j];
				cache[j] = get_char<CharT>(strings[j], depth);
			}
			for (unsigned j=0; j < 64; ++j) {
				const CharT ch = cache[j];
				BucketT* sub_bucket = static_cast<BucketT*>(
					new_node->buckets[ch]);
				if (not sub_bucket) {
					new_node->buckets[ch] = sub_bucket
						= new BucketT;
				}
				sub_bucket->push_back(strings[j]);
			}
		}
		for (; i < bucket_size; ++i) {
			unsigned char* ptr = bucket[i];
			const CharT ch = get_char<CharT>(ptr, depth);
			BucketT* sub_bucket = static_cast<BucketT*>(
				new_node->buckets[ch]);
			if (not sub_bucket) {
				new_node->buckets[ch] = sub_bucket
					= new BucketT;
			}
			sub_bucket->push_back(ptr);
		}
		return new_node;
	}
};

// Another burst variant: After bursting the bucket, immediately burst large
// sub buckets in a recursive fashion.
template <typename CharT>
struct BurstRecursive
{
	template <typename BucketT>
	TrieNode<CharT>*
	operator()(const BucketT& bucket, size_t depth) const
	{
		TrieNode<CharT>* new_node
			= BurstSimple<CharT>()(bucket, depth);
		const size_t threshold = std::max(
				//size_t(100), size_t(0.4f*bucket.size()));
				size_t(100), bucket.size()/2);
		for (unsigned i=0; i < max<CharT>::value; ++i) {
			assert(new_node->is_trie[i] == false);
			BucketT* sub_bucket = static_cast<BucketT*>(
					new_node->buckets[i]);
			if (not sub_bucket) continue;
			if (not is_end(i) and sub_bucket->size() > threshold) {
				new_node->buckets[i] =
					BurstRecursive<CharT>()(*sub_bucket,
							depth+sizeof(CharT));
				delete sub_bucket;
				new_node->is_trie[i] = true;
			}
		}
		return new_node;
	}
};

template <unsigned Threshold, typename BucketT,
          typename BurstImpl, typename CharT>
static inline void
insert(TrieNode<CharT>* root, unsigned char** strings, size_t n)
{
	for (size_t i=0; i < n; ++i) {
		unsigned char* str = strings[i];
		size_t depth = 0;
		CharT c = get_char<CharT>(str, 0);
		TrieNode<CharT>* node = root;
		while (node->is_trie[c]) {
			assert(not is_end(c));
			node = static_cast<TrieNode<CharT>*>(node->buckets[c]);
			depth += sizeof(CharT);
			c = get_char<CharT>(str, depth);
		}
		BucketT* bucket = static_cast<BucketT*>(node->buckets[c]);
		if (not bucket) {
			node->buckets[c] = bucket = new BucketT;
		}
		bucket->push_back(str);
		if (is_end(c)) continue;
		if (bucket->size() > Threshold) {
			node->buckets[c] = BurstImpl()(*bucket,
					depth+sizeof(CharT));
			node->is_trie[c] = true;
			delete bucket;
		}
	}
}

// Use a wrapper to std::copy(). I haven't implemented iterators for some of my
// containers, instead they have optimized copy(bucket, dst).
static inline void
copy(const std::vector<unsigned char*>& bucket, unsigned char** dst)
{
	std::copy(bucket.begin(), bucket.end(), dst);
}

// Traverses the trie and copies the strings back to the original string array.
// Nodes and buckets are deleted from memory during the traversal. The root
// node given to this function will also be deleted.
template <typename BucketT, typename SmallSort, typename CharT>
static unsigned char**
traverse(TrieNode<CharT>* node,
         unsigned char** dst,
         size_t depth,
         SmallSort small_sort)
{
	for (unsigned i=0; i < max<CharT>::value; ++i) {
		if (node->is_trie[i]) {
			dst = traverse<BucketT>(
				static_cast<TrieNode<CharT>*>(node->buckets[i]),
				dst, depth+sizeof(CharT), small_sort);
		} else {
			BucketT* bucket =
				static_cast<BucketT*>(node->buckets[i]);
			if (not bucket) continue;
			size_t bsize = bucket->size();
			copy(*bucket, dst);
			if (not is_end(i)) small_sort(dst, bsize, depth);
			dst += bsize;
			delete bucket;
		}
	}
	delete node;
	return dst;
}

#define SmallSort mkqsort
extern "C" void mkqsort(unsigned char**, int, int);

//#define SmallSort msd_CE2
//void msd_CE2(unsigned char**, size_t, size_t);

void burstsort_vector(unsigned char** strings, size_t n)
{
	typedef unsigned char CharT;
	typedef std::vector<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<8000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_brodnik(unsigned char** strings, size_t n)
{
	typedef unsigned char CharT;
	typedef vector_brodnik<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<16000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_bagwell(unsigned char** strings, size_t n)
{
	typedef unsigned char CharT;
	typedef vector_bagwell<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<16000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_vector_block(unsigned char** strings, size_t n)
{
	typedef unsigned char CharT;
	typedef vector_block<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<16000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_superalphabet_vector(unsigned char** strings, size_t n)
{
	typedef uint16_t CharT;
	typedef std::vector<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<32000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_superalphabet_brodnik(unsigned char** strings, size_t n)
{
	typedef uint16_t CharT;
	typedef vector_brodnik<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<32000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_superalphabet_bagwell(unsigned char** strings, size_t n)
{
	typedef uint16_t CharT;
	typedef vector_bagwell<unsigned char*> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<32000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}

void burstsort_superalphabet_vector_block(unsigned char** strings, size_t n)
{
	typedef uint16_t CharT;
	typedef vector_block<unsigned char*, 128> BucketT;
	typedef BurstSimple<CharT> BurstImpl;
	//typedef BurstRecursive<CharT> BurstImpl;
	TrieNode<CharT>* root = new TrieNode<CharT>;
	insert<32000, BucketT, BurstImpl>(root, strings, n);
	traverse<BucketT>(root, strings, 0, SmallSort);
}
<|endoftext|>


<commit_before>/*
 *    _aaaa,  _aa.  sa,  aaa              _aaaa,_  ac  .aa.   .aa.  .aa,  _a, sa
 *  .wWV!!!T  |Wm;  dQ[  $WF            _mWT!"?Y  ]QE  :Q#:   ]QW[  :WWk. ]Q[ dW
 * .jWf       :WW: .dQ[  dQ[           .mW(       )WE  :Q#:  .mSQh. :mWQa.]W[ dQ
 * |QW:       :Wm;  mQ[  dQ[           ]Qk        )Qmi_aQW:  <B:$Qc :WBWQ()W[ dQ
 * |W#:  .ww  ;WW;  dQ[  dQ[  .......  ]Qk        )QB?YYW#:  jf ]Qp.:mE)Qm]Q[ )W
 * +WQ;  :Wm  |Wm; .mQ[  dQ[ :qgggggga ]Qm.       ]WE  :Q# :=QasuQm;:Wk 3QQW[ )Y
 *  ]Wmi.:Wm  +$Q; .mW(  dQ[  !"!!"!!^ dQk,  ._   ]WE  :Q# :3D"!!$Qc.Wk -$WQ[
 *   "?????? ` "?!=m?!   ??'            -??????!  -?!  -?? -?'   "?"-?"  "??' "?
 *
 * Copyright (c) 2004 darkbits                              Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of darkbits nor the     :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * 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.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/widgets/button.hpp"
#include "guichan/mouseinput.hpp"
#include <iostream>

namespace gcn
{
  Button::Button()
  {
    addMouseListener(this);
    addKeyListener(this);
    adjustSize();

  } // end Button

  Button::Button(const std::string& text)
  {
    mText = text;
    setFocusable(true);
    adjustSize();

    x = 0;
    y = 0;
    mMove = false;

    addMouseListener(this);
    addKeyListener(this);

  } // end Button

  void Button::setText(const std::string& text)
  {
    mText = text;

  } // end setText

  void Button::draw(Graphics* graphics)
  {
    graphics->setFont(getFont());
    if (hasFocus())
    {
      Color c = getBackgroundColor() + 0x202020;
      graphics->setColor(c);
      graphics->fillRectangle(Rectangle(1, 1, getDimension().width-1, getDimension().height-1));

      graphics->setColor(c+0x303030);
      graphics->drawLine(0, 0, getDimension().width-1, 0);
      graphics->drawLine(0, 1, 0, getDimension().height-1);

      graphics->setColor(c*0.3);
      graphics->drawLine(getDimension().width-1, 1, getDimension().width-1, getDimension().height-1);
      graphics->drawLine(1, getDimension().height-1, getDimension().width-1, getDimension().height-1);
    }
    else if (hasMouse())
    {
      Color c = getBackgroundColor() + 0xff2090;
      graphics->setColor(c);
      graphics->fillRectangle(Rectangle(1, 1, getDimension().width-1, getDimension().height-1));

      graphics->setColor(c+0x303030);
      graphics->drawLine(0, 0, getDimension().width-1, 0);
      graphics->drawLine(0, 1, 0, getDimension().height-1);

      graphics->setColor(c*0.3);
      graphics->drawLine(getDimension().width-1, 1, getDimension().width-1, getDimension().height-1);
      graphics->drawLine(1, getDimension().height-1, getDimension().width-1, getDimension().height-1);
    }
    else
    {
      graphics->setColor(getBackgroundColor());
      graphics->fillRectangle(Rectangle(1, 1, getDimension().width-1, getDimension().height-1));

      graphics->setColor(getBackgroundColor()+0x303030);
      graphics->drawLine(0, 0, getDimension().width-1, 0);
      graphics->drawLine(0, 1, 0, getDimension().height-1);

      graphics->setColor(getBackgroundColor()*0.3);
      graphics->drawLine(getDimension().width-1, 1, getDimension().width-1, getDimension().height-1);
      graphics->drawLine(1, getDimension().height-1, getDimension().width-1, getDimension().height-1);
    }

    graphics->drawText(mText, 4, 4);

  } // end draw

  void Button::adjustSize()
  {
    setWidth(getFont()->getWidth(mText) + 8);
    setHeight(getFont()->getHeight() + 8);

  } // end adjustSize

  void Button::mouseClick(int x, int y, int button, int count)
  {
    generateAction();
    if( button == MouseInput::LEFT && count == 2)
    {
      mText = "Per died";
    }
    else if( button == MouseInput::WHEEL_UP )
    {
      mText = "Kill Per";
    }

    adjustSize();

  }

  void Button::mousePress(int x, int y, int button)
  {
    mMove = true;
    this->x = x;
    this->y = y;
  }

  void Button::mouseRelease(int x, int y, int button)
  {
    mMove = false;
    this->x = 0;
    this->y = 0;
  }

  void Button::mouseMotion(int x, int y)
  {
    int moveX = x - this->x;
    int moveY = y - this->y;

    if (mMove)
    {
      setPosition(getDimension().x + moveX, getDimension().y + moveY);
    }

  }

  void Button::lostFocus()
  {
    mMove = false;
    this->x = 0;
    this->y = 0;
  }

  void Button::keyPress(const Key& key)
  {
    if (key.getValue() == Key::ENTER)
    {
      generateAction();
      mText = "Pushed";
      adjustSize();
    }
  }

} // end gcn
<commit_msg>Button now behaves as an button should.<commit_after>/*
 *    _aaaa,  _aa.  sa,  aaa              _aaaa,_  ac  .aa.   .aa.  .aa,  _a, sa
 *  .wWV!!!T  |Wm;  dQ[  $WF            _mWT!"?Y  ]QE  :Q#:   ]QW[  :WWk. ]Q[ dW
 * .jWf       :WW: .dQ[  dQ[           .mW(       )WE  :Q#:  .mSQh. :mWQa.]W[ dQ
 * |QW:       :Wm;  mQ[  dQ[           ]Qk        )Qmi_aQW:  <B:$Qc :WBWQ()W[ dQ
 * |W#:  .ww  ;WW;  dQ[  dQ[  .......  ]Qk        )QB?YYW#:  jf ]Qp.:mE)Qm]Q[ )W
 * +WQ;  :Wm  |Wm; .mQ[  dQ[ :qgggggga ]Qm.       ]WE  :Q# :=QasuQm;:Wk 3QQW[ )Y
 *  ]Wmi.:Wm  +$Q; .mW(  dQ[  !"!!"!!^ dQk,  ._   ]WE  :Q# :3D"!!$Qc.Wk -$WQ[
 *   "?????? ` "?!=m?!   ??'            -??????!  -?!  -?? -?'   "?"-?"  "??' "?
 *
 * Copyright (c) 2004 darkbits                              Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of darkbits nor the     :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * 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.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/widgets/button.hpp"
#include "guichan/mouseinput.hpp"
#include <iostream>

namespace gcn
{
  Button::Button()
  {
    addMouseListener(this);
    addKeyListener(this);
    adjustSize();

  } // end Button

  Button::Button(const std::string& text)
  {
    mText = text;
    setFocusable(true);
    adjustSize();

    mMouseDown = false;
    mKeyDown = false;

    addMouseListener(this);
    addKeyListener(this);

  } // end Button

  void Button::setText(const std::string& text)
  {
    mText = text;

  } // end setText

  void Button::draw(Graphics* graphics)
  {
    graphics->setFont(getFont());

    Color faceColor = getBackgroundColor();
    Color highlightColor, shadowColor;

    if ((hasMouse() && mMouseDown) || mKeyDown)
    {
      faceColor = getBackgroundColor() - 0x303030;
      highlightColor = faceColor - 0x303030;
      shadowColor = faceColor + 0x303030;
    }
    else
    {
      highlightColor = faceColor + 0x303030;
      shadowColor = faceColor - 0x303030;
    }

    graphics->setColor(faceColor);
    graphics->fillRectangle(Rectangle(1, 1, getDimension().width-1, getDimension().height-1));

    graphics->setColor(highlightColor);
    graphics->drawLine(0, 0, getDimension().width-1, 0);
    graphics->drawLine(0, 1, 0, getDimension().height-1);

    graphics->setColor(shadowColor);
    graphics->drawLine(getDimension().width-1, 1, getDimension().width-1, getDimension().height-1);
    graphics->drawLine(1, getDimension().height-1, getDimension().width-1, getDimension().height-1);

    if ((hasMouse() && mMouseDown) || mKeyDown)
    {
      graphics->drawText(mText, 5, 5);
    }
    else
    {
      graphics->drawText(mText, 4, 4);

      if (hasFocus())
      {
        graphics->setColor(getForegroundColor());
        graphics->drawRectangle(Rectangle(2, 2, getDimension().width - 4, getDimension().height - 4));
      }
    }

  } // end draw

  void Button::adjustSize()
  {
    setWidth(getFont()->getWidth(mText) + 8);
    setHeight(getFont()->getHeight() + 8);

  } // end adjustSize

  void Button::mouseClick(int x, int y, int button, int count)
  {
    if (button == MouseInput::LEFT)
    {
      generateAction();
    }

  } // end mouseClick

  void Button::mousePress(int x, int y, int button)
  {
    if (button == MouseInput::LEFT)
    {
      mMouseDown = true;
    }

  } // end mousePress

  void Button::mouseRelease(int x, int y, int button)
  {
    if (button == MouseInput::LEFT)
    {
      mMouseDown = false;
    }

  } // end mouseRelease

  void Button::keyPress(const Key& key)
  {
    if (key.getValue() == Key::ENTER || key.getValue() == Key::SPACE)
    {
      mKeyDown = true;
   }

  } // end keyPress

  void Button::keyRelease(const Key& key)
  {
    if ((key.getValue() == Key::ENTER || key.getValue() == Key::SPACE) && mKeyDown)
    {
      mKeyDown = false;
      generateAction();
    }

  } // end keyRelease

  void Button::lostFocus()
  {
    mMouseDown = false;
    mKeyDown = false;

  } // end lostFocus

} // end gcn
<|endoftext|>


<commit_before>
#include "mesh_exporter.h"
#include "material_exporter.h"
#include "logger.h"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <assimp/../../code/BoostWorkaround/boost/lexical_cast.hpp>

namespace {
	void ExportScene(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*);
}

Assimp::Exporter::ExportFormatEntry Assimp2XML3D_desc = Assimp::Exporter::ExportFormatEntry(
	"xml",
	"XML representation of the scene, compatible for use with XML3D as an external asset.",
	"xml",
	ExportScene,
	0u);

namespace {
	void ExportScene(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) {
		XML3DExporter exp(scene, file);
		exp.Export();
		exp.writeFile();
	}
}

XML3DExporter::XML3DExporter(const aiScene* ai, const char* file) {
	aiCopyScene(ai, &scene);
	filename = file;
}

XML3DExporter::~XML3DExporter() {
	doc.Clear();
	aiFreeScene(scene);
}

void XML3DExporter::Export() {
	doc.InsertFirstChild(doc.NewDeclaration());
	tinyxml2::XMLElement* xml3d = doc.NewElement("xml3d");
	tinyxml2::XMLElement* defs = doc.NewElement("defs");
	tinyxml2::XMLElement* asset = doc.NewElement("asset");
	xml3d->InsertFirstChild(defs);
	xml3d->LinkEndChild(asset);
	doc.LinkEndChild(xml3d);

	std::string id(filename);
	id = id.substr(0, id.find_first_of('.'));
	asset->SetAttribute("id", id.c_str());

	removeDummyMaterial(scene);

	if (scene->HasMeshes()) {
		for (unsigned int i = 0; i < scene->mNumMeshes; i++) {
			XML3DMeshExporter mexp(this, scene->mMeshes[i]);
			tinyxml2::XMLElement* data = mexp.getAssetData();
			asset->InsertFirstChild(data);
		}
	}

	if (scene->HasMaterials()) {
		for (unsigned int i = 0; i < scene->mNumMaterials; i++) {
			XML3DMaterialExporter matExp(this, scene->mMaterials[i]);
			tinyxml2::XMLElement* material = matExp.getMaterial();
			defs->LinkEndChild(material);
			mNumberOfMaterialsExported++;
		}
	}

	// Flatten scene hierarchy into a list of assetmeshes
	Export(asset, scene->mRootNode, aiMatrix4x4());

	Logger::Info("Processed " + boost::lexical_cast<std::string>(mNumberOfMeshesExported) + " meshes and " +
		boost::lexical_cast<std::string>(mNumberOfMaterialsExported) + " materials.");
}

// Assimp will always generate a material even if it was instructed to ignore materials during the import process.
// To prevent this material from being exported when the --no-material flag was set we implicitly remove it from the scene
// by setting the material count to 0.
void XML3DExporter::removeDummyMaterial(aiScene* scene) {
	if (scene->mNumMaterials == 1) {
		aiMaterial* mat = scene->mMaterials[0];
		aiString name;
		mat->Get(AI_MATKEY_NAME, name);
		if (!strcmp(name.C_Str(), "Dummy_MaterialsRemoved")) {
			scene->mNumMaterials = 0; //Will cause HasMaterials to return false from now on
		}
	}
}

void XML3DExporter::Export(tinyxml2::XMLElement* parent, aiNode* an, const aiMatrix4x4& parentTransform) {
	// Flatten all non-mesh nodes while gathering the transformations

	aiMatrix4x4 t(an->mTransformation);
	t = parentTransform * t;

	for (unsigned int i = 0; i < an->mNumMeshes; i++) {
		XML3DMeshExporter mexp(this, scene->mMeshes[an->mMeshes[i]]);
		tinyxml2::XMLElement* mesh = mexp.getAssetMesh(&t);
		parent->LinkEndChild(mesh);
		mNumberOfMeshesExported++;
	}

	for (unsigned int i = 0; i < an->mNumChildren; i++) {
		Export(parent, an->mChildren[i], t);
	}
}

void XML3DExporter::writeFile() {
	doc.SaveFile(filename);
}

void XML3DExporter::stringToHTMLId(aiString& ai) {
	// Ensure the name is not empty and is safe to use as an HTML5 id string
	std::string str(ai.C_Str());

	if (!(str.length() > 0)) {
		str = "_Generated_Name_" + boost::lexical_cast<std::string>(mChangedNamesCounter++);
	}

	std::replace(str.begin(), str.end(), ' ', '_');

	if (usedNames.count(str) > 0) {
		str += "_" + boost::lexical_cast<std::string>(mChangedNamesCounter++);
		Logger::Warn("Renamed '" + str.substr(0, str.find_last_of("_")) + "' to '" + str + "' to avoid duplicate IDs");
	}
	usedNames.emplace(str, 'x');

	ai.Set(str);
}

<commit_msg>Add assetdata elements in ascending order to match assetmeshes<commit_after>
#include "mesh_exporter.h"
#include "material_exporter.h"
#include "logger.h"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <assimp/../../code/BoostWorkaround/boost/lexical_cast.hpp>

namespace {
	void ExportScene(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*);
}

Assimp::Exporter::ExportFormatEntry Assimp2XML3D_desc = Assimp::Exporter::ExportFormatEntry(
	"xml",
	"XML representation of the scene, compatible for use with XML3D as an external asset.",
	"xml",
	ExportScene,
	0u);

namespace {
	void ExportScene(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) {
		XML3DExporter exp(scene, file);
		exp.Export();
		exp.writeFile();
	}
}

XML3DExporter::XML3DExporter(const aiScene* ai, const char* file) {
	aiCopyScene(ai, &scene);
	filename = file;
}

XML3DExporter::~XML3DExporter() {
	doc.Clear();
	aiFreeScene(scene);
}

void XML3DExporter::Export() {
	doc.InsertFirstChild(doc.NewDeclaration());
	tinyxml2::XMLElement* xml3d = doc.NewElement("xml3d");
	tinyxml2::XMLElement* defs = doc.NewElement("defs");
	tinyxml2::XMLElement* asset = doc.NewElement("asset");
	xml3d->InsertFirstChild(defs);
	xml3d->LinkEndChild(asset);
	doc.LinkEndChild(xml3d);

	std::string id(filename);
	id = id.substr(0, id.find_first_of('.'));
	asset->SetAttribute("id", id.c_str());

	removeDummyMaterial(scene);

	if (scene->HasMeshes()) {
		for (unsigned int i = 0; i < scene->mNumMeshes; i++) {
			XML3DMeshExporter mexp(this, scene->mMeshes[i]);
			tinyxml2::XMLElement* data = mexp.getAssetData();
			asset->LinkEndChild(data);
		}
	}

	if (scene->HasMaterials()) {
		for (unsigned int i = 0; i < scene->mNumMaterials; i++) {
			XML3DMaterialExporter matExp(this, scene->mMaterials[i]);
			tinyxml2::XMLElement* material = matExp.getMaterial();
			defs->LinkEndChild(material);
			mNumberOfMaterialsExported++;
		}
	}

	// Flatten scene hierarchy into a list of assetmeshes
	Export(asset, scene->mRootNode, aiMatrix4x4());

	Logger::Info("Processed " + boost::lexical_cast<std::string>(mNumberOfMeshesExported) + " meshes and " +
		boost::lexical_cast<std::string>(mNumberOfMaterialsExported) + " materials.");
}

// Assimp will always generate a material even if it was instructed to ignore materials during the import process.
// To prevent this material from being exported when the --no-material flag was set we implicitly remove it from the scene
// by setting the material count to 0.
void XML3DExporter::removeDummyMaterial(aiScene* scene) {
	if (scene->mNumMaterials == 1) {
		aiMaterial* mat = scene->mMaterials[0];
		aiString name;
		mat->Get(AI_MATKEY_NAME, name);
		if (!strcmp(name.C_Str(), "Dummy_MaterialsRemoved")) {
			scene->mNumMaterials = 0; //Will cause HasMaterials to return false from now on
		}
	}
}

void XML3DExporter::Export(tinyxml2::XMLElement* parent, aiNode* an, const aiMatrix4x4& parentTransform) {
	// Flatten all non-mesh nodes while gathering the transformations

	aiMatrix4x4 t(an->mTransformation);
	t = parentTransform * t;

	for (unsigned int i = 0; i < an->mNumMeshes; i++) {
		XML3DMeshExporter mexp(this, scene->mMeshes[an->mMeshes[i]]);
		tinyxml2::XMLElement* mesh = mexp.getAssetMesh(&t);
		parent->LinkEndChild(mesh);
		mNumberOfMeshesExported++;
	}

	for (unsigned int i = 0; i < an->mNumChildren; i++) {
		Export(parent, an->mChildren[i], t);
	}
}

void XML3DExporter::writeFile() {
	doc.SaveFile(filename);
}

void XML3DExporter::stringToHTMLId(aiString& ai) {
	// Ensure the name is not empty and is safe to use as an HTML5 id string
	std::string str(ai.C_Str());

	if (!(str.length() > 0)) {
		str = "_Generated_Name_" + boost::lexical_cast<std::string>(mChangedNamesCounter++);
	}

	std::replace(str.begin(), str.end(), ' ', '_');

	if (usedNames.count(str) > 0) {
		str += "_" + boost::lexical_cast<std::string>(mChangedNamesCounter++);
		Logger::Warn("Renamed '" + str.substr(0, str.find_last_of("_")) + "' to '" + str + "' to avoid duplicate IDs");
	}
	usedNames.emplace(str, 'x');

	ai.Set(str);
}

<|endoftext|>


<commit_before>/*!
    \file timestamp.cpp
    \brief Timestamp implementation
    \author Ivan Shynkarenka
    \date 26.01.2016
    \copyright MIT License
*/

#include "time/timestamp.h"

#include "errors/exceptions.h"

#include <iostream>

#if defined(__APPLE__)
#include <mach/clock.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <math.h>
#include <time.h>
#elif defined(unix) || defined(__unix) || defined(__unix__)
#include <time.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#endif

namespace CppCommon {

//! @cond INTERNALS
namespace Internals {

#if defined(__APPLE__)

uint32_t CeilLog2(uint32_t x)
{
    uint32_t result = 0;

    --x;
    while (x > 0)
    {
        ++result;
        x >>= 1;
    }

    return result;
}

// This function returns the rational number inside the given interval with
// the smallest denominator (and smallest numerator breaks ties; correctness
// proof neglects floating-point errors).
mach_timebase_info_data_t BestFrac(double a, double b)
{
    if (floor(a) < floor(b))
    {
        mach_timebase_info_data_t rv = { (uint32_t)ceil(a), 1 };
        return rv;
    }

    double m = floor(a);
    mach_timebase_info_data_t next = BestFrac(1 / (b - m), 1 / (a - m));
    mach_timebase_info_data_t rv = { (int)m * next.numer + next.denom, next.numer };
    return rv;
}

// This is just less than the smallest thing we can multiply numer by without
// overflowing. CeilLog2(numer) = 64 - number of leading zeros of numer
uint64_t GetExpressibleSpan(uint32_t numer, uint32_t denom)
{
  uint64_t maxDiffWithoutOverflow = ((uint64_t)1 << (64 - CeilLog2(numer))) - 1;
  return maxDiffWithoutOverflow * numer / denom;
}

// The clock may run up to 0.1% faster or slower than the "exact" tick count.
// However, although the bound on the error is the same as for the pragmatic
// answer, the error is actually minimized over the given accuracy bound.
uint64_t PrepareTimebaseInfo(mach_timebase_info_data_t& tb)
{
    tb.numer = 0;
    tb.denom = 1;

    kern_return_t mtiStatus = mach_timebase_info(&tb);
    if (mtiStatus != KERN_SUCCESS)
        return 0;

    double frac = (double)tb.numer / tb.denom;
    uint64_t spanTarget = 315360000000000000llu;
    if (GetExpressibleSpan(tb.numer, tb.denom) >= spanTarget)
        return 0;

    for (double errorTarget = 1 / 1024.0; errorTarget > 0.000001;)
    {
        mach_timebase_info_data_t newFrac = BestFrac((1 - errorTarget) * frac, (1 + errorTarget) * frac);
        if (GetExpressibleSpan(newFrac.numer, newFrac.denom) < spanTarget)
            break;
        tb = newFrac;
        errorTarget = fabs((double)tb.numer / tb.denom - frac) / frac / 8;
    }

    return mach_absolute_time();
}

#endif

} // namespace Internals
//! @endcond

uint64_t Timestamp::utc()
{
#if defined(__APPLE__)
    clock_serv_t cclock;
    mach_timespec_t mts = { 0 };
    mach_port_t host_port = mach_host_self();
    if (host_port == MACH_PORT_NULL)
        throwex SystemException("Cannot get the current host port!");
    kern_return_t result = host_get_clock_service(host_port, CALENDAR_CLOCK, &cclock);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot get the current host clock service!");
    result = clock_get_time(cclock, &mts);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot get the current clock time!");
    mach_port_t task_port = mach_task_self();
    if (task_port == MACH_PORT_NULL)
        throwex SystemException("Cannot get the current task port!");
    result = mach_port_deallocate(task_port, cclock);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot release the current host clock service!");
    uint64_t result1 = ((uint64_t)mts.tv_sec * 1000 * 1000 * 1000) + mts.tv_nsec;
    std::cerr << "Timestamp: " << result1 << std::endl;
    return result1;
#elif defined(unix) || defined(__unix) || defined(__unix__)
    struct timespec timestamp;
    if (clock_gettime(CLOCK_REALTIME, &timestamp) != 0)
        throwex SystemException("Cannot get value of CLOCK_REALTIME timer!");
    return (timestamp.tv_sec * 1000 * 1000 * 1000) + timestamp.tv_nsec;
#elif defined(_WIN32) || defined(_WIN64)
    FILETIME ft;
    GetSystemTimePreciseAsFileTime(&ft);

    ULARGE_INTEGER result;
    result.LowPart = ft.dwLowDateTime;
    result.HighPart = ft.dwHighDateTime;
    return (result.QuadPart - 116444736000000000ull) * 100;
#endif
}

uint64_t Timestamp::local()
{
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    uint64_t timestamp = utc();

    // Adjust UTC time with local timezone offset
    struct tm local;
    time_t seconds = timestamp / (1000 * 1000 * 1000);
    if (localtime_r(&seconds, &local) != &local)
        throwex SystemException("Cannot convert CLOCK_REALTIME time to local date & time structure!");
    return timestamp + (local.tm_gmtoff * 1000 * 1000 * 1000);
#elif defined(_WIN32) || defined(_WIN64)
    FILETIME ft;
    GetSystemTimePreciseAsFileTime(&ft);

    FILETIME ft_local;
    if (!FileTimeToLocalFileTime(&ft, &ft_local))
        throwex SystemException("Cannot convert UTC file time to local file time structure!");

    ULARGE_INTEGER result;
    result.LowPart = ft_local.dwLowDateTime;
    result.HighPart = ft_local.dwHighDateTime;
    return (result.QuadPart - 116444736000000000ull) * 100;
#endif
}

uint64_t Timestamp::nano()
{
#if defined(__APPLE__)
    static mach_timebase_info_data_t info;
    static uint64_t bias = Internals::PrepareTimebaseInfo(info);
    return (mach_absolute_time() - bias) * info.numer / info.denom;
#elif defined(unix) || defined(__unix) || defined(__unix__)
    struct timespec timestamp = { 0 };
    if (clock_gettime(CLOCK_MONOTONIC, &timestamp) != 0)
        throwex SystemException("Cannot get value of CLOCK_MONOTONIC timer!");
    return (timestamp.tv_sec * 1000 * 1000 * 1000) + timestamp.tv_nsec;
#elif defined(_WIN32) || defined(_WIN64)
    static uint64_t offset = 0;
    static LARGE_INTEGER first = { 0 };
    static LARGE_INTEGER frequency = { 0 };
    static bool initialized = false;
    static bool qpc = true;

    if (!initialized)
    {
        // Calculate timestamp offset
        FILETIME timestamp;
        GetSystemTimePreciseAsFileTime(&timestamp);

        ULARGE_INTEGER result;
        result.LowPart = timestamp.dwLowDateTime;
        result.HighPart = timestamp.dwHighDateTime;

        // Convert 01.01.1601 to 01.01.1970
        result.QuadPart -= 116444736000000000ll;
        offset = result.QuadPart * 100;

        // Setup performance counter
        qpc = QueryPerformanceFrequency(&frequency) && QueryPerformanceCounter(&first);

        initialized = true;
    }

    if (qpc)
    {
        LARGE_INTEGER timestamp = { 0 };
        QueryPerformanceCounter(&timestamp);
        timestamp.QuadPart -= first.QuadPart;
        return offset + ((timestamp.QuadPart * 1000 * 1000 * 1000) / frequency.QuadPart);
    }
    else
        return offset;
#else
    #error Unsupported platform
#endif
}

uint64_t Timestamp::rdts()
{
#if defined(_MSC_VER)
    return __rdtsc();
#elif defined(__i386__)
    uint64_t x;
    __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
    return x;
#elif defined(__x86_64__)
    unsigned hi, lo;
    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    return ((uint64_t)lo) | (((uint64_t)hi) << 32);
#endif
}

} // namespace CppCommon
<commit_msg>Fix OSX build<commit_after>/*!
    \file timestamp.cpp
    \brief Timestamp implementation
    \author Ivan Shynkarenka
    \date 26.01.2016
    \copyright MIT License
*/

#include "time/timestamp.h"

#include "errors/exceptions.h"

#if defined(__APPLE__)
#include <mach/clock.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <math.h>
#include <time.h>
#elif defined(unix) || defined(__unix) || defined(__unix__)
#include <time.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#endif

namespace CppCommon {

//! @cond INTERNALS
namespace Internals {

#if defined(__APPLE__)

uint32_t CeilLog2(uint32_t x)
{
    uint32_t result = 0;

    --x;
    while (x > 0)
    {
        ++result;
        x >>= 1;
    }

    return result;
}

// This function returns the rational number inside the given interval with
// the smallest denominator (and smallest numerator breaks ties; correctness
// proof neglects floating-point errors).
mach_timebase_info_data_t BestFrac(double a, double b)
{
    if (floor(a) < floor(b))
    {
        mach_timebase_info_data_t rv = { (uint32_t)ceil(a), 1 };
        return rv;
    }

    double m = floor(a);
    mach_timebase_info_data_t next = BestFrac(1 / (b - m), 1 / (a - m));
    mach_timebase_info_data_t rv = { (int)m * next.numer + next.denom, next.numer };
    return rv;
}

// This is just less than the smallest thing we can multiply numer by without
// overflowing. CeilLog2(numer) = 64 - number of leading zeros of numer
uint64_t GetExpressibleSpan(uint32_t numer, uint32_t denom)
{
  uint64_t maxDiffWithoutOverflow = ((uint64_t)1 << (64 - CeilLog2(numer))) - 1;
  return maxDiffWithoutOverflow * numer / denom;
}

// The clock may run up to 0.1% faster or slower than the "exact" tick count.
// However, although the bound on the error is the same as for the pragmatic
// answer, the error is actually minimized over the given accuracy bound.
uint64_t PrepareTimebaseInfo(mach_timebase_info_data_t& tb)
{
    tb.numer = 0;
    tb.denom = 1;

    kern_return_t mtiStatus = mach_timebase_info(&tb);
    if (mtiStatus != KERN_SUCCESS)
        return 0;

    double frac = (double)tb.numer / tb.denom;
    uint64_t spanTarget = 315360000000000000llu;
    if (GetExpressibleSpan(tb.numer, tb.denom) >= spanTarget)
        return 0;

    for (double errorTarget = 1 / 1024.0; errorTarget > 0.000001;)
    {
        mach_timebase_info_data_t newFrac = BestFrac((1 - errorTarget) * frac, (1 + errorTarget) * frac);
        if (GetExpressibleSpan(newFrac.numer, newFrac.denom) < spanTarget)
            break;
        tb = newFrac;
        errorTarget = fabs((double)tb.numer / tb.denom - frac) / frac / 8;
    }

    return mach_absolute_time();
}

#endif

} // namespace Internals
//! @endcond

uint64_t Timestamp::utc()
{
#if defined(__APPLE__)
    clock_serv_t cclock;
    mach_timespec_t mts = { 0 };
    mach_port_t host_port = mach_host_self();
    if (host_port == MACH_PORT_NULL)
        throwex SystemException("Cannot get the current host port!");
    kern_return_t result = host_get_clock_service(host_port, CALENDAR_CLOCK, &cclock);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot get the current host clock service!");
    result = clock_get_time(cclock, &mts);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot get the current clock time!");
    mach_port_t task_port = mach_task_self();
    if (task_port == MACH_PORT_NULL)
        throwex SystemException("Cannot get the current task port!");
    result = mach_port_deallocate(task_port, cclock);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot release the current host clock service!");
    return ((uint64_t)mts.tv_sec * 1000 * 1000 * 1000) + mts.tv_nsec;
#elif defined(unix) || defined(__unix) || defined(__unix__)
    struct timespec timestamp;
    if (clock_gettime(CLOCK_REALTIME, &timestamp) != 0)
        throwex SystemException("Cannot get value of CLOCK_REALTIME timer!");
    return (timestamp.tv_sec * 1000 * 1000 * 1000) + timestamp.tv_nsec;
#elif defined(_WIN32) || defined(_WIN64)
    FILETIME ft;
    GetSystemTimePreciseAsFileTime(&ft);

    ULARGE_INTEGER result;
    result.LowPart = ft.dwLowDateTime;
    result.HighPart = ft.dwHighDateTime;
    return (result.QuadPart - 116444736000000000ull) * 100;
#endif
}

uint64_t Timestamp::local()
{
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    uint64_t timestamp = utc();

    // Adjust UTC time with local timezone offset
    struct tm local;
    time_t seconds = timestamp / (1000 * 1000 * 1000);
    if (localtime_r(&seconds, &local) != &local)
        throwex SystemException("Cannot convert CLOCK_REALTIME time to local date & time structure!");
    return timestamp + (local.tm_gmtoff * 1000 * 1000 * 1000);
#elif defined(_WIN32) || defined(_WIN64)
    FILETIME ft;
    GetSystemTimePreciseAsFileTime(&ft);

    FILETIME ft_local;
    if (!FileTimeToLocalFileTime(&ft, &ft_local))
        throwex SystemException("Cannot convert UTC file time to local file time structure!");

    ULARGE_INTEGER result;
    result.LowPart = ft_local.dwLowDateTime;
    result.HighPart = ft_local.dwHighDateTime;
    return (result.QuadPart - 116444736000000000ull) * 100;
#endif
}

uint64_t Timestamp::nano()
{
#if defined(__APPLE__)
    static mach_timebase_info_data_t info;
    static uint64_t bias = Internals::PrepareTimebaseInfo(info);
    return (mach_absolute_time() - bias) * info.numer / info.denom;
#elif defined(unix) || defined(__unix) || defined(__unix__)
    struct timespec timestamp = { 0 };
    if (clock_gettime(CLOCK_MONOTONIC, &timestamp) != 0)
        throwex SystemException("Cannot get value of CLOCK_MONOTONIC timer!");
    return (timestamp.tv_sec * 1000 * 1000 * 1000) + timestamp.tv_nsec;
#elif defined(_WIN32) || defined(_WIN64)
    static uint64_t offset = 0;
    static LARGE_INTEGER first = { 0 };
    static LARGE_INTEGER frequency = { 0 };
    static bool initialized = false;
    static bool qpc = true;

    if (!initialized)
    {
        // Calculate timestamp offset
        FILETIME timestamp;
        GetSystemTimePreciseAsFileTime(&timestamp);

        ULARGE_INTEGER result;
        result.LowPart = timestamp.dwLowDateTime;
        result.HighPart = timestamp.dwHighDateTime;

        // Convert 01.01.1601 to 01.01.1970
        result.QuadPart -= 116444736000000000ll;
        offset = result.QuadPart * 100;

        // Setup performance counter
        qpc = QueryPerformanceFrequency(&frequency) && QueryPerformanceCounter(&first);

        initialized = true;
    }

    if (qpc)
    {
        LARGE_INTEGER timestamp = { 0 };
        QueryPerformanceCounter(&timestamp);
        timestamp.QuadPart -= first.QuadPart;
        return offset + ((timestamp.QuadPart * 1000 * 1000 * 1000) / frequency.QuadPart);
    }
    else
        return offset;
#else
    #error Unsupported platform
#endif
}

uint64_t Timestamp::rdts()
{
#if defined(_MSC_VER)
    return __rdtsc();
#elif defined(__i386__)
    uint64_t x;
    __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
    return x;
#elif defined(__x86_64__)
    unsigned hi, lo;
    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    return ((uint64_t)lo) | (((uint64_t)hi) << 32);
#endif
}

} // namespace CppCommon
<|endoftext|>


<commit_before>/* Copyright (c) 2009-2013, Fortylines LLC
   All rights reserved.

   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 fortylines 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 Fortylines LLC ''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 Fortylines LLC 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. */

#include "document.hh"
#include "checkstyle.hh"
#include "markup.hh"
#include "slice.hh"
#include "decorator.hh"

/** Check source files according to coding standards.

    Primary Author(s): Sebastien Mirolo <smirolo@fortylines.com>
*/

namespace {

class errTokWriter : public tero::errTokListener {
public:
	typedef std::map<int,std::string> annotationsType;
	annotationsType& annotations;
	boost::filesystem::path filename;
	bool record;
	int lineNum;
	std::string frag;

public:
	explicit errTokWriter( annotationsType& a,
						   const boost::filesystem::path& f )
		: annotations(a), filename(f), record(false) {}

    void newline( const char *line, int first, int last ) {
    }

    void token( tero::errToken token, const char *line,
				int first, int last, bool fragment ) {
		if( fragment ) {
			frag += std::string(&line[first],last - first);
		} else {
			std::string tokval;
			if( !frag.empty() ) {
				tokval = frag + std::string(&line[first],last - first);
				frag = "";
			} else {
				tokval = std::string(&line[first],last - first);
			}
			switch( token ) {
			case tero::errFilename:
				record = ( filename == boost::filesystem::path(tokval) );
				break;;
			case tero::errLineNum:
				if( record ) {
					lineNum = atoi(tokval.c_str());
				}
				break;
			case tero::errMessage:
				if( record ) {
					annotations[lineNum] += tokval;
				}
				break;
			default:
                /* Nothing to do excepts shutup gcc warnings. */
                break;
			}
		}
    }
};

}; // anonymous

namespace tero {

const char *licenseCodeTitles[] = {
    "unknown",
    "MIT",
    "BSD 2-Clause",
    "BSD 3-Clause",
    "Proprietary"
};

void checker::cache() {

    static const boost::regex licenses_regex[] = {
        // MIT license
        // -----------
boost::regex(
"\\s*Copyright \\(c\\) (\\d+(?:-\\d+)?), ([^#]*)"
" Permission is hereby granted, free of charge, to any person obtaining a copy"
" of this software and associated documentation files \\(the \"Software\"\\),"
" to deal in the Software without restriction, including without limitation"
" the rights to use, copy, modify, merge, publish, distribute, sublicense,"
" and/or sell copies of the Software, and to permit persons to whom the"
" Software is furnished to do so, subject to the following conditions:"
" The above copyright notice and this permission notice shall be included in"
" all copies or substantial portions of the Software\\."
" THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR"
" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,"
" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\\. IN NO EVENT SHALL THE"
" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER"
" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,"
" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN"
" THE SOFTWARE\\.\\s*"),

        // BSD 2-Clause
        // ------------
        boost::regex(
"\\s*Copyright \\(c\\) (\\d+(?:-\\d+)?), ([^#]*)"
" All rights reserved\\."
" Redistribution and use in source and binary forms, with or without"
" modification, are permitted provided that the following conditions are met:"
" 1\\. Redistributions of source code must retain the above copyright notice,"
" this list of conditions and the following disclaimer\\."
" 2\\. 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\\."
" 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\\.\\s*"),

        // BSD 3-Clause
        // ------------
        boost::regex(
"\\s*Copyright \\(c\\) (\\d+(?:-\\d+)?), ([^#]*)"
" All rights reserved\\."
" Redistribution and use in source and binary forms, with or without"
" modification, are permitted provided that the following conditions are met:"
" 1\\. Redistributions of source code must retain the above copyright notice,"
" this list of conditions and the following disclaimer\\."
" 2\\. 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\\."
" 3\\. Neither the name of the copyright holder 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\\.\\s*"),

        // Proprietary
        // -----------
        boost::regex(
"\\s*Copyright \\(c\\) (\\d+(?:-\\d+)?), ([^#]*)"
" All rights reserved\\.\\s*"),
    };

    boost::smatch m;
    std::string text = licenseText.str();
    for( licenseCode license = MITLicense; license < 5; ++license ) {
        if( boost::regex_match(text, m, licenses_regex[license - 1]) ) {
            licenseType = license;
            dates = m.str(1);
            grantor = m.str(2);
            break;
        }
    }
    cached = true;
}

void checker::normalize( const char *line, int first, int last )
{
    std::string s(&line[first], &line[last]);
    if( state == start ) {
        boost::smatch m;
        if( !boost::regex_search(s, m, boost::regex("Copyright")) ) return;
        state = readLicense;
    }
    while( first < last ) {
        switch( state ) {
        case normalizeLicense:
            while( first < last && isspace(line[first]) ) ++first;
            state = readLicense;
            break;
        case readLicense:
            while( first < last && !isspace(line[first]) ) {
                licenseText << line[first++];
            }
            licenseText << ' ';
            state = normalizeLicense;
            break;
        default:
            /* Nothing to do except prevent gcc from complaining. */
            return;
        }
    }
}

cppChecker::cppChecker()
    : comment(emptyLine),
      tokenizer(*this)

{
}

void cppChecker::newline(const char *line, int first, int last ) {
    switch( state ) {
    case readLicense:
        licenseText << ' ';
        state = normalizeLicense;
        break;
    default:
        /* Nothing to do except prevent gcc from complaining. */
        break;
    }
    ++nbLines;
    if( comment == codeLine ) ++nbCodeLines;
    comment = emptyLine;
}

void cppChecker::token( cppToken token, const char *line,
                        int first, int last, bool fragment ) {
    switch( token ) {
    case cppComment:
        normalize(line, first, last);
        if( (state == readLicense || state == normalizeLicense)
            && !fragment ) state = doneLicense;
        /* XXX we donot mark comment lines correctly but it does not
           matter because if there is any code on the line, it will
           be correctly marked as a "codeLine". */
        if( fragment ) comment = commentLine;
        break;
    default:
        comment = codeLine;
        switch( state ) {
        case readLicense:
            state = doneLicense;
            break;
        default:
            /* Nothing to do except prevent gcc from complaining. */
            break;
        }
        break;
    }
}

void shChecker::newline(const char *line, int first, int last )
{
    switch( state ) {
    case readLicense:
        licenseText << ' ';
        state = normalizeLicense;
        break;
    default:
        /* Nothing to do except prevent gcc from complaining. */
        break;
    }
    ++nbLines;
    /* \todo count codeLines... */
}

void shChecker::token( shToken token, const char *line,
                       int first, int last, bool fragment )
{
    switch( token ) {
    case shComment:
        if( first < last && line[first] == '#' ) ++first;
        normalize(line, first, last);
        if( (state == readLicense || state == normalizeLicense)
            && !fragment ) state = doneLicense;
        break;
    case shCode:
        state = doneLicense;
        break;
    default:
        /* Nothing to do excepts shutup gcc warnings. */
        break;
    }
}

void checkstyle::addDir( session& s,
    const boost::filesystem::path& pathname ) const {
}

void checkstyle::addFile( session& s,
    const boost::filesystem::path& pathname ) const {
    using namespace boost::filesystem;

    if( state == start ) {
        s.out() << html::p()
                << html::table();
        s.out() << html::tr()
                << html::th() << html::th::end
                << html::th() << "license" << html::th::end
                << html::th() << "code lines" << html::th::end
                << html::th() << "total lines" << html::th::end
                << html::tr::end;
        state = toplevelFiles;
    }
    dispatchDoc::instance()->fetch(s,"check",s.asUrl(pathname));
}

void checkstyle::flush( session& s ) const
{
    if( state != start ) {
        s.out() << html::table::end
                << html::p::end;
    }
}

void checkstyleFetch( session& s, const url& name )
{
    checkstyle p;
    p.fetch(s,s.abspath(name));
}

void lintAnnotate::init( session& s,
						 const boost::filesystem::path& key,
						 std::istream& info )
{
	errTokWriter w(super::annotations,key);
	errTokenizer tok(w);

	char buffer[4096];
	while( !info.eof() ) {
		info.read(buffer,4096);
		tok.tokenize(buffer,info.gcount());
	}
}

lintAnnotate::lintAnnotate( session& s,
							const boost::filesystem::path& key,
							std::istream& info )
	: super() {
	init(s,key,info);
}

lintAnnotate::lintAnnotate( session& s,
							const boost::filesystem::path& key,
							std::istream& info,
							std::basic_ostream<char>& o )
	: super(o) {
	init(s,key,info);
}

}
<commit_msg>fix: casting enum to int<commit_after>/* Copyright (c) 2009-2013, Fortylines LLC
   All rights reserved.

   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 fortylines 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 Fortylines LLC ''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 Fortylines LLC 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. */

#include "document.hh"
#include "checkstyle.hh"
#include "markup.hh"
#include "slice.hh"
#include "decorator.hh"

/** Check source files according to coding standards.

    Primary Author(s): Sebastien Mirolo <smirolo@fortylines.com>
*/

namespace {

class errTokWriter : public tero::errTokListener {
public:
	typedef std::map<int,std::string> annotationsType;
	annotationsType& annotations;
	boost::filesystem::path filename;
	bool record;
	int lineNum;
	std::string frag;

public:
	explicit errTokWriter( annotationsType& a,
						   const boost::filesystem::path& f )
		: annotations(a), filename(f), record(false) {}

    void newline( const char *line, int first, int last ) {
    }

    void token( tero::errToken token, const char *line,
				int first, int last, bool fragment ) {
		if( fragment ) {
			frag += std::string(&line[first],last - first);
		} else {
			std::string tokval;
			if( !frag.empty() ) {
				tokval = frag + std::string(&line[first],last - first);
				frag = "";
			} else {
				tokval = std::string(&line[first],last - first);
			}
			switch( token ) {
			case tero::errFilename:
				record = ( filename == boost::filesystem::path(tokval) );
				break;;
			case tero::errLineNum:
				if( record ) {
					lineNum = atoi(tokval.c_str());
				}
				break;
			case tero::errMessage:
				if( record ) {
					annotations[lineNum] += tokval;
				}
				break;
			default:
                /* Nothing to do excepts shutup gcc warnings. */
                break;
			}
		}
    }
};

}; // anonymous

namespace tero {

const char *licenseCodeTitles[] = {
    "unknown",
    "MIT",
    "BSD 2-Clause",
    "BSD 3-Clause",
    "Proprietary"
};

void checker::cache() {

    static const boost::regex licenses_regex[] = {
        // MIT license
        // -----------
boost::regex(
"\\s*Copyright \\(c\\) (\\d+(?:-\\d+)?), ([^#]*)"
" Permission is hereby granted, free of charge, to any person obtaining a copy"
" of this software and associated documentation files \\(the \"Software\"\\),"
" to deal in the Software without restriction, including without limitation"
" the rights to use, copy, modify, merge, publish, distribute, sublicense,"
" and/or sell copies of the Software, and to permit persons to whom the"
" Software is furnished to do so, subject to the following conditions:"
" The above copyright notice and this permission notice shall be included in"
" all copies or substantial portions of the Software\\."
" THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR"
" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,"
" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\\. IN NO EVENT SHALL THE"
" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER"
" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,"
" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN"
" THE SOFTWARE\\.\\s*"),

        // BSD 2-Clause
        // ------------
        boost::regex(
"\\s*Copyright \\(c\\) (\\d+(?:-\\d+)?), ([^#]*)"
" All rights reserved\\."
" Redistribution and use in source and binary forms, with or without"
" modification, are permitted provided that the following conditions are met:"
" 1\\. Redistributions of source code must retain the above copyright notice,"
" this list of conditions and the following disclaimer\\."
" 2\\. 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\\."
" 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\\.\\s*"),

        // BSD 3-Clause
        // ------------
        boost::regex(
"\\s*Copyright \\(c\\) (\\d+(?:-\\d+)?), ([^#]*)"
" All rights reserved\\."
" Redistribution and use in source and binary forms, with or without"
" modification, are permitted provided that the following conditions are met:"
" 1\\. Redistributions of source code must retain the above copyright notice,"
" this list of conditions and the following disclaimer\\."
" 2\\. 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\\."
" 3\\. Neither the name of the copyright holder 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\\.\\s*"),

        // Proprietary
        // -----------
        boost::regex(
"\\s*Copyright \\(c\\) (\\d+(?:-\\d+)?), ([^#]*)"
" All rights reserved\\.\\s*"),
    };

    boost::smatch m;
    std::string text = licenseText.str();
    for( int license = MITLicense; license < 5; ++license ) {
        if( boost::regex_match(text, m, licenses_regex[license - 1]) ) {
            licenseType = (licenseCode)license;
            dates = m.str(1);
            grantor = m.str(2);
            break;
        }
    }
    cached = true;
}

void checker::normalize( const char *line, int first, int last )
{
    std::string s(&line[first], &line[last]);
    if( state == start ) {
        boost::smatch m;
        if( !boost::regex_search(s, m, boost::regex("Copyright")) ) return;
        state = readLicense;
    }
    while( first < last ) {
        switch( state ) {
        case normalizeLicense:
            while( first < last && isspace(line[first]) ) ++first;
            state = readLicense;
            break;
        case readLicense:
            while( first < last && !isspace(line[first]) ) {
                licenseText << line[first++];
            }
            licenseText << ' ';
            state = normalizeLicense;
            break;
        default:
            /* Nothing to do except prevent gcc from complaining. */
            return;
        }
    }
}

cppChecker::cppChecker()
    : comment(emptyLine),
      tokenizer(*this)

{
}

void cppChecker::newline(const char *line, int first, int last ) {
    switch( state ) {
    case readLicense:
        licenseText << ' ';
        state = normalizeLicense;
        break;
    default:
        /* Nothing to do except prevent gcc from complaining. */
        break;
    }
    ++nbLines;
    if( comment == codeLine ) ++nbCodeLines;
    comment = emptyLine;
}

void cppChecker::token( cppToken token, const char *line,
                        int first, int last, bool fragment ) {
    switch( token ) {
    case cppComment:
        normalize(line, first, last);
        if( (state == readLicense || state == normalizeLicense)
            && !fragment ) state = doneLicense;
        /* XXX we donot mark comment lines correctly but it does not
           matter because if there is any code on the line, it will
           be correctly marked as a "codeLine". */
        if( fragment ) comment = commentLine;
        break;
    default:
        comment = codeLine;
        switch( state ) {
        case readLicense:
            state = doneLicense;
            break;
        default:
            /* Nothing to do except prevent gcc from complaining. */
            break;
        }
        break;
    }
}

void shChecker::newline(const char *line, int first, int last )
{
    switch( state ) {
    case readLicense:
        licenseText << ' ';
        state = normalizeLicense;
        break;
    default:
        /* Nothing to do except prevent gcc from complaining. */
        break;
    }
    ++nbLines;
    /* \todo count codeLines... */
}

void shChecker::token( shToken token, const char *line,
                       int first, int last, bool fragment )
{
    switch( token ) {
    case shComment:
        if( first < last && line[first] == '#' ) ++first;
        normalize(line, first, last);
        if( (state == readLicense || state == normalizeLicense)
            && !fragment ) state = doneLicense;
        break;
    case shCode:
        state = doneLicense;
        break;
    default:
        /* Nothing to do excepts shutup gcc warnings. */
        break;
    }
}

void checkstyle::addDir( session& s,
    const boost::filesystem::path& pathname ) const {
}

void checkstyle::addFile( session& s,
    const boost::filesystem::path& pathname ) const {
    using namespace boost::filesystem;

    if( state == start ) {
        s.out() << html::p()
                << html::table();
        s.out() << html::tr()
                << html::th() << html::th::end
                << html::th() << "license" << html::th::end
                << html::th() << "code lines" << html::th::end
                << html::th() << "total lines" << html::th::end
                << html::tr::end;
        state = toplevelFiles;
    }
    dispatchDoc::instance()->fetch(s,"check",s.asUrl(pathname));
}

void checkstyle::flush( session& s ) const
{
    if( state != start ) {
        s.out() << html::table::end
                << html::p::end;
    }
}

void checkstyleFetch( session& s, const url& name )
{
    checkstyle p;
    p.fetch(s,s.abspath(name));
}

void lintAnnotate::init( session& s,
						 const boost::filesystem::path& key,
						 std::istream& info )
{
	errTokWriter w(super::annotations,key);
	errTokenizer tok(w);

	char buffer[4096];
	while( !info.eof() ) {
		info.read(buffer,4096);
		tok.tokenize(buffer,info.gcount());
	}
}

lintAnnotate::lintAnnotate( session& s,
							const boost::filesystem::path& key,
							std::istream& info )
	: super() {
	init(s,key,info);
}

lintAnnotate::lintAnnotate( session& s,
							const boost::filesystem::path& key,
							std::istream& info,
							std::basic_ostream<char>& o )
	: super(o) {
	init(s,key,info);
}

}
<|endoftext|>