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

#include "labelhash.hh"

using namespace khmer;

/*
 * @camillescott
 * Might be time for a refactor: could do a general consume_fasta
 * function which accepts a consume_sequence function pointer as a parameter
 */

void
LabelHash::consume_fasta_and_tag_with_labels(
  std:: string const  &filename,
  unsigned int	      &total_reads, unsigned long long	&n_consumed,
  CallbackFn	      callback,	    void *		callback_data
)
{
  khmer:: Config    &the_config	  = khmer:: get_active_config( );

  // Note: Always assume only 1 thread if invoked this way.
  IParser *	  parser =
  IParser::get_parser(
    filename, 1, the_config.get_reads_input_buffer_size( ),
    the_config.get_reads_parser_trace_level( )
  );

  consume_fasta_and_tag_with_labels(
    parser,
    total_reads, n_consumed,
    callback, callback_data
  );

  delete parser;
}

void
LabelHash::consume_fasta_and_tag_with_labels(
    read_parsers:: IParser *  parser,
    unsigned int		    &total_reads,   unsigned long long	&n_consumed,
    CallbackFn		    callback,	    void *		callback_data
  )
  {
    Hasher		  &hasher		=
    _get_hasher( parser->uuid( ) );
    unsigned int		  total_reads_LOCAL	= 0;
  #if (0) // Note: Used with callback - currently disabled.
    unsigned long long int  n_consumed_LOCAL	= 0;
  #endif
    Read			  read;

    // TODO? Delete the following assignments.
    total_reads = 0;
    n_consumed = 0;

    hasher.trace_logger(
      TraceLogger:: TLVL_DEBUG2,
      "Starting trace of 'consume_fasta_and_tag_with_labels'....\n"
    );

    Label _tag_label = 0;

    Label * the_label;
    // Iterate through the reads and consume their k-mers.
    while (!parser->is_complete( ))
    {
      unsigned long long this_n_consumed   = 0;

      read = parser->get_next_read( );

      if (check_and_normalize_read( read.sequence ))
      {
        // TODO: make threadsafe!
        the_label = check_and_allocate_label(_tag_label);
        consume_sequence_and_tag_with_labels( read.sequence,
					      this_n_consumed,
					      *the_label );
	    _tag_label++;

  #ifdef WITH_INTERNAL_METRICS
        hasher.pmetrics.start_timers( );
  #endif
  #if (0) // Note: Used with callback - currently disabled.
        n_consumed_LOCAL  = __sync_add_and_fetch( &n_consumed, this_n_consumed );
  #else
        __sync_add_and_fetch( &n_consumed, this_n_consumed );
  #endif
        total_reads_LOCAL = __sync_add_and_fetch( &total_reads, 1 );
  #ifdef WITH_INTERNAL_METRICS
        hasher.pmetrics.stop_timers( );
        hasher.pmetrics.accumulate_timer_deltas(
	  (uint32_t)HashTablePerformanceMetrics:: MKEY_TIME_UPDATE_TALLIES
        );
  #endif
      }

      if (0 == (total_reads_LOCAL % 10000))
        hasher.trace_logger(
	  TraceLogger:: TLVL_DEBUG3,
	  "Total number of reads processed: %llu\n",
	  (unsigned long long int)total_reads_LOCAL
        );

      // TODO: Figure out alternative to callback into Python VM
      //       Cannot use in multi-threaded operation.
  #if (0)
        // run callback, if specified
        if (total_reads_TL % CALLBACK_PERIOD == 0 && callback) {
	  std::cout << "n tags: " << all_tags.size() << "\n";
	  try {
	    callback("consume_fasta_and_tag_with_labels", callback_data, total_reads_TL,
		     n_consumed);
	  } catch (...) {
	    delete parser;
	    throw;
	  }
        }
  #endif // 0

    } // while reads left for parser

  }

void LabelHash::consume_partitioned_fasta_and_tag_with_labels(const std::string &filename,
					  unsigned int &total_reads,
					  unsigned long long &n_consumed,
					  CallbackFn callback,
					  void * callback_data)
{
  total_reads = 0;
  n_consumed = 0;

  IParser* parser = IParser::get_parser(filename.c_str());
  Read read;

  string seq = "";

  // reset the master subset partition
  delete partition;
  partition = new SubsetPartition(this);

  //
  // iterate through the FASTA file & consume the reads.
  //
  Label * c;
  PartitionID p;
  while(!parser->is_complete())  {
    read = parser->get_next_read();
    seq = read.sequence;

    if (check_and_normalize_read(seq)) {
      // First, figure out what the partition is (if non-zero), and save that.
      p = _parse_partition_id(read.name);
      c = check_and_allocate_label(p);

      consume_sequence_and_tag_with_labels( seq,
					      n_consumed,
					      *c );
    }

    // reset the sequence info, increment read number
    total_reads++;

    // run callback, if specified
    if (total_reads % CALLBACK_PERIOD == 0 && callback) {
      try {
        callback("consume_partitioned_fasta_and_tag_with_labels", callback_data,
        total_reads, n_consumed);
      } catch (...) {
	delete parser;
        throw;
      }
    }
  }

  // @cswelcher TODO: check that deallocate LabelPtrMap is correct
  delete parser;
}

// @cswelcher: double-check -- is it valid to pull the address from a reference?
void LabelHash::link_tag_and_label(HashIntoType& kmer, Label& kmer_label) {
  tag_labels.insert(TagLabelPtrPair(kmer, &kmer_label));
  label_tag_ptrs.insert(LabelTagPtrPair(kmer_label, &kmer));
}

void LabelHash::consume_sequence_and_tag_with_labels(const std::string& seq,
					unsigned long long& n_consumed,
					Label& current_label,
					SeenSet * found_tags)
  {
    bool is_new_kmer;
    bool kmer_tagged;

    KMerIterator kmers(seq.c_str(), _ksize);
    HashIntoType kmer;

    unsigned int since = _tag_density / 2 + 1;

    while(!kmers.done()) {
      kmer = kmers.next();

      if ((is_new_kmer = test_and_set_bits( kmer )))
        ++n_consumed;

  #if (1)
      if (is_new_kmer) {
        ++since;
      } else {
        ACQUIRE_ALL_TAGS_SPIN_LOCK
        kmer_tagged = set_contains(all_tags, kmer);
        RELEASE_ALL_TAGS_SPIN_LOCK
        if (kmer_tagged) {
	      since = 1;

	      // Labeling code
	      // TODO: MAKE THREADSAFE!

	      if (!_cmap_contains_label(tag_labels, kmer, current_label)) {
	        ACQUIRE_TAG_COLORS_SPIN_LOCK
	        link_tag_and_label(kmer, current_label);
	        RELEASE_TAG_COLORS_SPIN_LOCK
	      }
	      if (found_tags) {
	        found_tags->insert(kmer);
	      }
        }  else ++since;
      }
  #else
      if (!is_new_kmer && set_contains(all_tags, kmer)) {
        since = 1;
        if (found_tags) { found_tags->insert(kmer); }
      } else {
        since++;
      }
  #endif
      //
      if (since >= _tag_density) {
        ACQUIRE_ALL_TAGS_SPIN_LOCK
        all_tags.insert(kmer);
        RELEASE_ALL_TAGS_SPIN_LOCK

        // Labeling code
        // TODO: MAKE THREADSAFE!
        ACQUIRE_TAG_COLORS_SPIN_LOCK
        link_tag_and_label(kmer, current_label);
        RELEASE_TAG_COLORS_SPIN_LOCK

        if (found_tags) { found_tags->insert(kmer); }
        since = 1;
      }

    } // iteration over kmers

    if (since >= _tag_density/2 - 1) {
      ACQUIRE_ALL_TAGS_SPIN_LOCK
      all_tags.insert(kmer);	// insert the last k-mer, too.
      RELEASE_ALL_TAGS_SPIN_LOCK

      // Label code: TODO: MAKE THREADSAFE!
      link_tag_and_label(kmer, current_label);

      if (found_tags) { found_tags->insert(kmer); }
    }
  }
/*
 * Find all labels associated with the sequence
 * For now, check /every/ k-mer with find_all_tags
 * THIS SUCKS AND IT'S YOUR FAULT @CTB
 */
unsigned int LabelHash::sweep_sequence_for_labels(const std::string& seq,
					LabelPtrSet& found_labels,
					bool break_on_stoptags,
					bool stop_big_traversals) {

    SeenSet tagged_kmers;
    //LabelPtrSet found_labels;

    HashIntoType kmer_f, kmer_r, kmer;

    KMerIterator kmers(seq.c_str(), _ksize);
    std::string kmer_s;
    // keep a list of kmers which have already been traversed
    SeenSet traversed_kmers;
    while (!kmers.done()) {
      kmer = kmers.next();
      kmer_s = _revhash(kmer, _ksize);
      _hash(kmer_s.c_str(), _ksize, kmer_f, kmer_r);

      // don't even try traversing from k-mers not in the hashtable
      //traversed_kmers.clear();
      if (get_count(uniqify_rc(kmer_f,kmer_r))) {
        partition->find_all_tags(kmer_f, kmer_r, tagged_kmers,
                   all_tags, break_on_stoptags, stop_big_traversals);
        traverse_labels_and_resolve(tagged_kmers, found_labels);
      }
    }
    return traversed_kmers.size();
}

unsigned int LabelHash::sweep_label_neighborhood(const std::string& seq,
                                                  LabelPtrSet& found_labels,
                                                  unsigned int range,
                                                  bool break_on_stoptags,
                                                  bool stop_big_traversals) {

    SeenSet tagged_kmers;
    unsigned int num_traversed;
    num_traversed = partition->sweep_for_tags(seq, tagged_kmers, all_tags,
                              range, break_on_stoptags, stop_big_traversals);
    traverse_labels_and_resolve(tagged_kmers, found_labels);
    //printf("range=%u ", range);
    if (range == 0) {
      assert(num_traversed == seq.length()-ksize()+1);
    }
    tagged_kmers.clear();
    return num_traversed;
}

LabelPtrSet LabelHash::get_tag_labels(const HashIntoType& tag) {
  LabelPtrSet labels;
  //unsigned int num_labels;
  _get_tag_labels(tag, tag_labels, labels);
  return labels;
}

TagPtrSet LabelHash::get_label_tags(const Label& label) {
  TagPtrSet tags;
  //unsigned int num_tags;
  _get_tags_from_label(label, label_tag_ptrs, tags);
  return tags;
}

void LabelHash::traverse_labels_and_resolve(const SeenSet& tagged_kmers,
                                              LabelPtrSet& found_labels) {

  SeenSet::const_iterator si;
  unsigned int num_labels = 0;
  for (si=tagged_kmers.begin(); si!=tagged_kmers.end(); ++si) {
    HashIntoType tag = *si;
    // get the labels associated with this tag
    num_labels = _get_tag_labels(tag, tag_labels, found_labels);
    if (num_labels > 1) {
      // reconcile labels
      // for now do nothing ha
    }
  }
}

<commit_msg>now the namespaces are nice fishjord<commit_after>//
// This file is part of khmer, http://github.com/ged-lab/khmer/, and is
// Copyright (C) Michigan State University, 2009-2013. It is licensed under
// the three-clause BSD license; see doc/LICENSE.txt. Contact: ctb@msu.edu
//

#include "labelhash.hh"

using namespace khmer;
using namespace khmer:: read_parsers;

/*
 * @camillescott
 * Might be time for a refactor: could do a general consume_fasta
 * function which accepts a consume_sequence function pointer as a parameter
 */

void
LabelHash::consume_fasta_and_tag_with_labels(
  std:: string const  &filename,
  unsigned int	      &total_reads, unsigned long long	&n_consumed,
  CallbackFn	      callback,	    void *		callback_data
)
{
  khmer:: Config    &the_config	  = khmer:: get_active_config( );

  // Note: Always assume only 1 thread if invoked this way.
  IParser *	  parser =
  IParser::get_parser(
    filename, 1, the_config.get_reads_input_buffer_size( ),
    the_config.get_reads_parser_trace_level( )
  );

  consume_fasta_and_tag_with_labels(
    parser,
    total_reads, n_consumed,
    callback, callback_data
  );

  delete parser;
}

void
LabelHash::consume_fasta_and_tag_with_labels(
    read_parsers:: IParser *  parser,
    unsigned int		    &total_reads,   unsigned long long	&n_consumed,
    CallbackFn		    callback,	    void *		callback_data
  )
  {
    Hasher		  &hasher		=
    _get_hasher( parser->uuid( ) );
    unsigned int		  total_reads_LOCAL	= 0;
  #if (0) // Note: Used with callback - currently disabled.
    unsigned long long int  n_consumed_LOCAL	= 0;
  #endif
    Read			  read;

    // TODO? Delete the following assignments.
    total_reads = 0;
    n_consumed = 0;

    hasher.trace_logger(
      TraceLogger:: TLVL_DEBUG2,
      "Starting trace of 'consume_fasta_and_tag_with_labels'....\n"
    );

    Label _tag_label = 0;

    Label * the_label;
    // Iterate through the reads and consume their k-mers.
    while (!parser->is_complete( ))
    {
      unsigned long long this_n_consumed   = 0;

      read = parser->get_next_read( );

      if (check_and_normalize_read( read.sequence ))
      {
        // TODO: make threadsafe!
        the_label = check_and_allocate_label(_tag_label);
        consume_sequence_and_tag_with_labels( read.sequence,
					      this_n_consumed,
					      *the_label );
	    _tag_label++;

  #ifdef WITH_INTERNAL_METRICS
        hasher.pmetrics.start_timers( );
  #endif
  #if (0) // Note: Used with callback - currently disabled.
        n_consumed_LOCAL  = __sync_add_and_fetch( &n_consumed, this_n_consumed );
  #else
        __sync_add_and_fetch( &n_consumed, this_n_consumed );
  #endif
        total_reads_LOCAL = __sync_add_and_fetch( &total_reads, 1 );
  #ifdef WITH_INTERNAL_METRICS
        hasher.pmetrics.stop_timers( );
        hasher.pmetrics.accumulate_timer_deltas(
	  (uint32_t)HashTablePerformanceMetrics:: MKEY_TIME_UPDATE_TALLIES
        );
  #endif
      }

      if (0 == (total_reads_LOCAL % 10000))
        hasher.trace_logger(
	  TraceLogger:: TLVL_DEBUG3,
	  "Total number of reads processed: %llu\n",
	  (unsigned long long int)total_reads_LOCAL
        );

      // TODO: Figure out alternative to callback into Python VM
      //       Cannot use in multi-threaded operation.
  #if (0)
        // run callback, if specified
        if (total_reads_TL % CALLBACK_PERIOD == 0 && callback) {
	  std::cout << "n tags: " << all_tags.size() << "\n";
	  try {
	    callback("consume_fasta_and_tag_with_labels", callback_data, total_reads_TL,
		     n_consumed);
	  } catch (...) {
	    delete parser;
	    throw;
	  }
        }
  #endif // 0

    } // while reads left for parser

  }

void LabelHash::consume_partitioned_fasta_and_tag_with_labels(const std::string &filename,
					  unsigned int &total_reads,
					  unsigned long long &n_consumed,
					  CallbackFn callback,
					  void * callback_data)
{
  total_reads = 0;
  n_consumed = 0;

  IParser* parser = IParser::get_parser(filename.c_str());
  Read read;

  std::string seq = "";

  // reset the master subset partition
  delete partition;
  partition = new SubsetPartition(this);

  //
  // iterate through the FASTA file & consume the reads.
  //
  Label * c;
  PartitionID p;
  while(!parser->is_complete())  {
    read = parser->get_next_read();
    seq = read.sequence;

    if (check_and_normalize_read(seq)) {
      // First, figure out what the partition is (if non-zero), and save that.
      p = _parse_partition_id(read.name);
      c = check_and_allocate_label(p);

      consume_sequence_and_tag_with_labels( seq,
					      n_consumed,
					      *c );
    }

    // reset the sequence info, increment read number
    total_reads++;

    // run callback, if specified
    if (total_reads % CALLBACK_PERIOD == 0 && callback) {
      try {
        callback("consume_partitioned_fasta_and_tag_with_labels", callback_data,
        total_reads, n_consumed);
      } catch (...) {
	delete parser;
        throw;
      }
    }
  }

  // @cswelcher TODO: check that deallocate LabelPtrMap is correct
  delete parser;
}

// @cswelcher: double-check -- is it valid to pull the address from a reference?
void LabelHash::link_tag_and_label(HashIntoType& kmer, Label& kmer_label) {
  tag_labels.insert(TagLabelPtrPair(kmer, &kmer_label));
  label_tag_ptrs.insert(LabelTagPtrPair(kmer_label, &kmer));
}

void LabelHash::consume_sequence_and_tag_with_labels(const std::string& seq,
					unsigned long long& n_consumed,
					Label& current_label,
					SeenSet * found_tags)
  {
    bool is_new_kmer;
    bool kmer_tagged;

    KMerIterator kmers(seq.c_str(), _ksize);
    HashIntoType kmer;

    unsigned int since = _tag_density / 2 + 1;

    while(!kmers.done()) {
      kmer = kmers.next();

      if ((is_new_kmer = test_and_set_bits( kmer )))
        ++n_consumed;

  #if (1)
      if (is_new_kmer) {
        ++since;
      } else {
        ACQUIRE_ALL_TAGS_SPIN_LOCK
        kmer_tagged = set_contains(all_tags, kmer);
        RELEASE_ALL_TAGS_SPIN_LOCK
        if (kmer_tagged) {
	      since = 1;

	      // Labeling code
	      // TODO: MAKE THREADSAFE!

	      if (!_cmap_contains_label(tag_labels, kmer, current_label)) {
	        ACQUIRE_TAG_COLORS_SPIN_LOCK
	        link_tag_and_label(kmer, current_label);
	        RELEASE_TAG_COLORS_SPIN_LOCK
	      }
	      if (found_tags) {
	        found_tags->insert(kmer);
	      }
        }  else ++since;
      }
  #else
      if (!is_new_kmer && set_contains(all_tags, kmer)) {
        since = 1;
        if (found_tags) { found_tags->insert(kmer); }
      } else {
        since++;
      }
  #endif
      //
      if (since >= _tag_density) {
        ACQUIRE_ALL_TAGS_SPIN_LOCK
        all_tags.insert(kmer);
        RELEASE_ALL_TAGS_SPIN_LOCK

        // Labeling code
        // TODO: MAKE THREADSAFE!
        ACQUIRE_TAG_COLORS_SPIN_LOCK
        link_tag_and_label(kmer, current_label);
        RELEASE_TAG_COLORS_SPIN_LOCK

        if (found_tags) { found_tags->insert(kmer); }
        since = 1;
      }

    } // iteration over kmers

    if (since >= _tag_density/2 - 1) {
      ACQUIRE_ALL_TAGS_SPIN_LOCK
      all_tags.insert(kmer);	// insert the last k-mer, too.
      RELEASE_ALL_TAGS_SPIN_LOCK

      // Label code: TODO: MAKE THREADSAFE!
      link_tag_and_label(kmer, current_label);

      if (found_tags) { found_tags->insert(kmer); }
    }
  }
/*
 * Find all labels associated with the sequence
 * For now, check /every/ k-mer with find_all_tags
 * THIS SUCKS AND IT'S YOUR FAULT @CTB
 */
unsigned int LabelHash::sweep_sequence_for_labels(const std::string& seq,
					LabelPtrSet& found_labels,
					bool break_on_stoptags,
					bool stop_big_traversals) {

    SeenSet tagged_kmers;
    //LabelPtrSet found_labels;

    HashIntoType kmer_f, kmer_r, kmer;

    KMerIterator kmers(seq.c_str(), _ksize);
    std::string kmer_s;
    // keep a list of kmers which have already been traversed
    SeenSet traversed_kmers;
    while (!kmers.done()) {
      kmer = kmers.next();
      kmer_s = _revhash(kmer, _ksize);
      _hash(kmer_s.c_str(), _ksize, kmer_f, kmer_r);

      // don't even try traversing from k-mers not in the hashtable
      //traversed_kmers.clear();
      if (get_count(uniqify_rc(kmer_f,kmer_r))) {
        partition->find_all_tags(kmer_f, kmer_r, tagged_kmers,
                   all_tags, break_on_stoptags, stop_big_traversals);
        traverse_labels_and_resolve(tagged_kmers, found_labels);
      }
    }
    return traversed_kmers.size();
}

unsigned int LabelHash::sweep_label_neighborhood(const std::string& seq,
                                                  LabelPtrSet& found_labels,
                                                  unsigned int range,
                                                  bool break_on_stoptags,
                                                  bool stop_big_traversals) {

    SeenSet tagged_kmers;
    unsigned int num_traversed;
    num_traversed = partition->sweep_for_tags(seq, tagged_kmers, all_tags,
                              range, break_on_stoptags, stop_big_traversals);
    traverse_labels_and_resolve(tagged_kmers, found_labels);
    //printf("range=%u ", range);
    if (range == 0) {
      assert(num_traversed == seq.length()-ksize()+1);
    }
    tagged_kmers.clear();
    return num_traversed;
}

LabelPtrSet LabelHash::get_tag_labels(const HashIntoType& tag) {
  LabelPtrSet labels;
  //unsigned int num_labels;
  _get_tag_labels(tag, tag_labels, labels);
  return labels;
}

TagPtrSet LabelHash::get_label_tags(const Label& label) {
  TagPtrSet tags;
  //unsigned int num_tags;
  _get_tags_from_label(label, label_tag_ptrs, tags);
  return tags;
}

void LabelHash::traverse_labels_and_resolve(const SeenSet& tagged_kmers,
                                              LabelPtrSet& found_labels) {

  SeenSet::const_iterator si;
  unsigned int num_labels = 0;
  for (si=tagged_kmers.begin(); si!=tagged_kmers.end(); ++si) {
    HashIntoType tag = *si;
    // get the labels associated with this tag
    num_labels = _get_tag_labels(tag, tag_labels, found_labels);
    if (num_labels > 1) {
      // reconcile labels
      // for now do nothing ha
    }
  }
}

<|endoftext|>


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

#include "modules/common/adapters/adapter.h"

#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "modules/common/adapters/adapter_gflags.h"
#include "modules/localization/proto/localization.pb.h"

namespace apollo {
namespace common {
namespace adapter {

using IntegerAdapter = Adapter<int>;

TEST(AdapterTest, Empty) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  EXPECT_TRUE(adapter.Empty());
}

TEST(AdapterTest, Observe) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  adapter.OnReceive(173);

  // Before calling Observe.
  EXPECT_TRUE(adapter.Empty());

  // After calling Observe.
  adapter.Observe();
  EXPECT_FALSE(adapter.Empty());
}

TEST(AdapterTest, GetLatestObserved) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  adapter.OnReceive(173);

  adapter.Observe();
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(173, adapter.GetLatestObserved());

  adapter.OnReceive(5);
  adapter.OnReceive(7);
  // Before calling Observe() again.
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(173, adapter.GetLatestObserved());
  adapter.Observe();
  // After calling Observe() again.
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(7, adapter.GetLatestObserved());
}

TEST(AdapterTest, History) {
  IntegerAdapter adapter("Integer", "integer_topic", 3);
  adapter.OnReceive(1);
  adapter.OnReceive(2);

  adapter.Observe();
  {
    // Currently the history contains [2, 1].
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(2, history.size());
    EXPECT_EQ(2, *history[0]);
    EXPECT_EQ(1, *history[1]);
  }

  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(3);
  adapter.OnReceive(4);
  adapter.OnReceive(5);

  {
    // Although there are more messages, without calling Observe,
    // the history is still [2, 1].
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(2, history.size());
    EXPECT_EQ(2, *history[0]);
    EXPECT_EQ(1, *history[1]);
  }

  adapter.Observe();
  {
    // After calling Observe(), the history starts from 5. Since we only
    // maintain 3 elements in this adapter, 1 and 2 will be thrown out.
    //
    // History should be 5, 4, 3.
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(3, history.size());
    EXPECT_EQ(5, *history[0]);
    EXPECT_EQ(4, *history[1]);
    EXPECT_EQ(3, *history[2]);
  }
}

TEST(AdapterTest, Callback) {
  IntegerAdapter adapter("Integer", "integer_topic", 3);

  // Set the callback to act as a counter of messages.
  int count = 0;
  adapter.SetCallback([&count](int x) { count += x; });

  adapter.OnReceive(11);
  adapter.OnReceive(41);
  adapter.OnReceive(31);
  EXPECT_EQ(11 + 41 + 31, count);
}

using MyLocalizationAdapter = Adapter<localization::LocalizationEstimate>;

TEST(AdapterTest, Dump) {
  FLAGS_enable_adapter_dump = true;
  std::string temp_dir = std::getenv("TEST_TMPDIR");

  MyLocalizationAdapter adapter("local", "local_topic", 3, temp_dir);
  localization::LocalizationEstimate loaded;

  localization::LocalizationEstimate msg;

  msg.mutable_header()->set_sequence_num(17);
  adapter.OnReceive(msg);
  apollo::common::util::GetProtoFromASCIIFile(temp_dir + "/local/17.pb.txt",
                                              &loaded);
  EXPECT_EQ(17, loaded.header().sequence_num());

  msg.mutable_header()->set_sequence_num(23);
  adapter.OnReceive(msg);
  apollo::common::util::GetProtoFromASCIIFile(temp_dir + "/local/23.pb.txt",
                                              &loaded);
  EXPECT_EQ(23, loaded.header().sequence_num());
}

}  // namespace adapter
}  // namespace common
}  // namespace apollo
<commit_msg>Fix adapter_test. (#405)<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/common/adapters/adapter.h"

#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "modules/common/adapters/adapter_gflags.h"
#include "modules/localization/proto/localization.pb.h"

namespace apollo {
namespace common {
namespace adapter {

using IntegerAdapter = Adapter<int>;

TEST(AdapterTest, Empty) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  EXPECT_TRUE(adapter.Empty());
}

TEST(AdapterTest, Observe) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  adapter.OnReceive(173);

  // Before calling Observe.
  EXPECT_TRUE(adapter.Empty());

  // After calling Observe.
  adapter.Observe();
  EXPECT_FALSE(adapter.Empty());
}

TEST(AdapterTest, GetLatestObserved) {
  IntegerAdapter adapter("Integer", "integer_topic", 10);
  adapter.OnReceive(173);

  adapter.Observe();
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(173, adapter.GetLatestObserved());

  adapter.OnReceive(5);
  adapter.OnReceive(7);
  // Before calling Observe() again.
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(173, adapter.GetLatestObserved());
  adapter.Observe();
  // After calling Observe() again.
  EXPECT_FALSE(adapter.Empty());
  EXPECT_EQ(7, adapter.GetLatestObserved());
}

TEST(AdapterTest, History) {
  IntegerAdapter adapter("Integer", "integer_topic", 3);
  adapter.OnReceive(1);
  adapter.OnReceive(2);

  adapter.Observe();
  {
    // Currently the history contains [2, 1].
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(2, history.size());
    EXPECT_EQ(2, *history[0]);
    EXPECT_EQ(1, *history[1]);
  }

  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(0);
  adapter.OnReceive(3);
  adapter.OnReceive(4);
  adapter.OnReceive(5);

  {
    // Although there are more messages, without calling Observe,
    // the history is still [2, 1].
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(2, history.size());
    EXPECT_EQ(2, *history[0]);
    EXPECT_EQ(1, *history[1]);
  }

  adapter.Observe();
  {
    // After calling Observe(), the history starts from 5. Since we only
    // maintain 3 elements in this adapter, 1 and 2 will be thrown out.
    //
    // History should be 5, 4, 3.
    std::vector<std::shared_ptr<int>> history(adapter.begin(), adapter.end());
    EXPECT_EQ(3, history.size());
    EXPECT_EQ(5, *history[0]);
    EXPECT_EQ(4, *history[1]);
    EXPECT_EQ(3, *history[2]);
  }
}

TEST(AdapterTest, Callback) {
  IntegerAdapter adapter("Integer", "integer_topic", 3);

  // Set the callback to act as a counter of messages.
  int count = 0;
  adapter.AddCallback([&count](int x) { count += x; });

  adapter.OnReceive(11);
  adapter.OnReceive(41);
  adapter.OnReceive(31);
  EXPECT_EQ(11 + 41 + 31, count);
}

using MyLocalizationAdapter = Adapter<localization::LocalizationEstimate>;

TEST(AdapterTest, Dump) {
  FLAGS_enable_adapter_dump = true;
  std::string temp_dir = std::getenv("TEST_TMPDIR");

  MyLocalizationAdapter adapter("local", "local_topic", 3, temp_dir);
  localization::LocalizationEstimate loaded;

  localization::LocalizationEstimate msg;

  msg.mutable_header()->set_sequence_num(17);
  adapter.OnReceive(msg);
  apollo::common::util::GetProtoFromASCIIFile(temp_dir + "/local/17.pb.txt",
                                              &loaded);
  EXPECT_EQ(17, loaded.header().sequence_num());

  msg.mutable_header()->set_sequence_num(23);
  adapter.OnReceive(msg);
  apollo::common::util::GetProtoFromASCIIFile(temp_dir + "/local/23.pb.txt",
                                              &loaded);
  EXPECT_EQ(23, loaded.header().sequence_num());
}

}  // namespace adapter
}  // namespace common
}  // namespace apollo
<|endoftext|>


<commit_before>/*
   This file is part of the clazy static checker.

  Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
  Author: Sérgio Martins <sergio.martins@kdab.com>

  Copyright (C) 2015 Sergio Martins <smartins@kde.org>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include "HierarchyUtils.h"
#include "clazy_stl.h"
#include <clang/AST/ParentMap.h>

using namespace std;
using namespace clang;

Stmt *HierarchyUtils::parent(ParentMap *map, Stmt *s, unsigned int depth)
{
    if (!s)
        return nullptr;

    return depth == 0 ? s
                      : parent(map, map->getParent(s), depth - 1);
}

clang::Stmt * HierarchyUtils::getFirstChildAtDepth(clang::Stmt *s, unsigned int depth)
{
    if (depth == 0 || !s)
        return s;

    return s->child_begin() == s->child_end() ? nullptr : getFirstChildAtDepth(*s->child_begin(), --depth);
}

bool HierarchyUtils::isChildOf(Stmt *child, Stmt *parent)
{
    if (!child || !parent)
        return false;

    for (auto c = parent->child_begin(), end = parent->child_end(); c != end; ++c) {
        if (*c == child || isChildOf(child, *c))
            return true;
    }

    return false;
}

bool HierarchyUtils::isParentOfMemberFunctionCall(Stmt *stm, const std::string &name)
{
    if (!stm)
        return false;

    auto expr = dyn_cast<MemberExpr>(stm);

    if (expr) {
        auto namedDecl = dyn_cast<NamedDecl>(expr->getMemberDecl());
        if (namedDecl && namedDecl->getNameAsString() == name)
            return true;
    }

    return clazy_std::any_of(stm->children(), [name] (Stmt *child) {
        return isParentOfMemberFunctionCall(child, name);
    });

    return false;
}

clang::Stmt *HierarchyUtils::getFirstChild(clang::Stmt *parent)
{
    if (!parent)
        return nullptr;

    auto it = parent->child_begin();
    return it == parent->child_end() ? nullptr : *it;
}
<commit_msg>Use any_of<commit_after>/*
   This file is part of the clazy static checker.

  Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
  Author: Sérgio Martins <sergio.martins@kdab.com>

  Copyright (C) 2015 Sergio Martins <smartins@kde.org>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include "HierarchyUtils.h"
#include "clazy_stl.h"
#include <clang/AST/ParentMap.h>

using namespace std;
using namespace clang;

Stmt *HierarchyUtils::parent(ParentMap *map, Stmt *s, unsigned int depth)
{
    if (!s)
        return nullptr;

    return depth == 0 ? s
                      : parent(map, map->getParent(s), depth - 1);
}

clang::Stmt * HierarchyUtils::getFirstChildAtDepth(clang::Stmt *s, unsigned int depth)
{
    if (depth == 0 || !s)
        return s;

    return s->child_begin() == s->child_end() ? nullptr : getFirstChildAtDepth(*s->child_begin(), --depth);
}

bool HierarchyUtils::isChildOf(Stmt *child, Stmt *parent)
{
    if (!child || !parent)
        return false;

    return clazy_std::any_of(parent->children(), [child](Stmt *c) {
        return c == child || HierarchyUtils::isChildOf(child, c);
    });
}

bool HierarchyUtils::isParentOfMemberFunctionCall(Stmt *stm, const std::string &name)
{
    if (!stm)
        return false;

    auto expr = dyn_cast<MemberExpr>(stm);

    if (expr) {
        auto namedDecl = dyn_cast<NamedDecl>(expr->getMemberDecl());
        if (namedDecl && namedDecl->getNameAsString() == name)
            return true;
    }

    return clazy_std::any_of(stm->children(), [name] (Stmt *child) {
        return isParentOfMemberFunctionCall(child, name);
    });

    return false;
}

clang::Stmt *HierarchyUtils::getFirstChild(clang::Stmt *parent)
{
    if (!parent)
        return nullptr;

    auto it = parent->child_begin();
    return it == parent->child_end() ? nullptr : *it;
}
<|endoftext|>


<commit_before><commit_msg>consider comment lines with starting whitespace(s)<commit_after><|endoftext|>


<commit_before><commit_msg>Update data.cpp<commit_after><|endoftext|>


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

// -----------------------------------------------------------------------------
// This file provides implementations of the font resolution members of
// SkFontHost by using the fontconfig[1] library. Fontconfig is usually found
// on Linux systems and handles configuration, parsing and caching issues
// involved with enumerating and matching fonts.
//
// [1] http://fontconfig.org
// -----------------------------------------------------------------------------

#include <map>
#include <string>

#include <fontconfig/fontconfig.h>

#include "SkDescriptor.h"
#include "SkFontHost.h"
#include "SkMMapStream.h"
#include "SkPaint.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkThread.h"
#include "SkTSearch.h"

// This is an extern from SkFontHost_FreeType
SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);

// -----------------------------------------------------------------------------
// The rest of Skia requires that fonts be identified by a unique unsigned id
// and that we be able to load them given the id. What we actually get from
// fontconfig is the filename of the font so we keep a locked map from
// filenames to fileid numbers and back.
//
// Note that there's also a unique id in the SkTypeface. This is unique over
// both filename and style. Thus we encode that id as (fileid << 8) | style.
// Although truetype fonts can support multiple faces in a single file, at the
// moment Skia doesn't.
// -----------------------------------------------------------------------------
static SkMutex global_fc_map_lock;
static std::map<std::string, unsigned> global_fc_map;
static std::map<unsigned, std::string> global_fc_map_inverted;
static unsigned global_fc_map_next_id = 0;

// This is the maximum size of the font cache.
static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024;  // 2MB

static unsigned UniqueIdToFileId(unsigned uniqueid)
{
    return uniqueid >> 8;
}

static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid)
{
    return static_cast<SkTypeface::Style>(uniqueid & 0xff);
}

static unsigned FileIdAndStyleToUniqueId(unsigned fileid,
                                         SkTypeface::Style style)
{
    // TODO(agl/brettw) bug 6291: This assertion fails for unknown reasons
    // on ChromeFontTest.LoadArial. This should be fixed.
    //SkASSERT(style & 0xff == style);
    return (fileid << 8) | static_cast<int>(style);
}

class FontConfigTypeface : public SkTypeface {
public:
    FontConfigTypeface(Style style, uint32_t id)
        : SkTypeface(style, id)
    { }
};

// -----------------------------------------------------------------------------
// Find a matching font where @type (one of FC_*) is equal to @value. For a
// list of types, see http://fontconfig.org/fontconfig-devel/x19.html#AEN27.
// The variable arguments are a list of triples, just like the first three
// arguments, and must be NULL terminated.
//
// For example, FontMatchString(FC_FILE, FcTypeString,
//                              "/usr/share/fonts/myfont.ttf", NULL);
// -----------------------------------------------------------------------------
static FcPattern* FontMatch(bool is_fallback,
                            const char* type, FcType vtype, const void* value,
                            ...)
{
    va_list ap;
    va_start(ap, value);

    FcPattern* pattern = FcPatternCreate();
    bool family_requested = false;

    for (;;) {
        FcValue fcvalue;
        fcvalue.type = vtype;
        switch (vtype) {
            case FcTypeString:
                fcvalue.u.s = (FcChar8*) value;
                break;
            case FcTypeInteger:
                fcvalue.u.i = (int) value;
                break;
            default:
                SkASSERT(!"FontMatch unhandled type");
        }
        FcPatternAdd(pattern, type, fcvalue, 0);

        if (vtype == FcTypeString && strcmp(type, FC_FAMILY) == 0)
            family_requested = true;

        type = va_arg(ap, const char *);
        if (!type)
            break;
        // FcType is promoted to int when passed through ...
        vtype = static_cast<FcType>(va_arg(ap, int));
        value = va_arg(ap, const void *);
    };
    va_end(ap);

    FcConfigSubstitute(0, pattern, FcMatchPattern);
    FcDefaultSubstitute(pattern);

    // Font matching:
    // CSS often specifies a fallback list of families:
    //    font-family: a, b, c, serif;
    // However, fontconfig will always do its best to find *a* font when asked
    // for something so we need a way to tell if the match which it has found is
    // "good enough" for us. Otherwise, we can return NULL which gets piped up
    // and lets WebKit know to try the next CSS family name. However, fontconfig
    // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
    // wish to support that.
    //
    // Thus, if a specific family is requested we set @family_requested. Then we
    // record two strings: the family name after config processing and the
    // family name after resolving. If the two are equal, it's a good match.
    //
    // So consider the case where a user has mapped Arial to Helvetica in their
    // config.
    //    requested family: "Arial"
    //    post_config_family: "Helvetica"
    //    post_match_family: "Helvetica"
    //      -> good match
    //
    // and for a missing font:
    //    requested family: "Monaco"
    //    post_config_family: "Monaco"
    //    post_match_family: "Times New Roman"
    //      -> BAD match
    FcChar8* post_config_family;
    FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family);

    FcResult result;
    FcPattern* match = FcFontMatch(0, pattern, &result);
    if (!match) {
        FcPatternDestroy(pattern);
        return NULL;
    }

    FcChar8* post_match_family;
    FcPatternGetString(match, FC_FAMILY, 0, &post_match_family);
    const bool family_names_match =
        !family_requested ?
        true :
        strcasecmp((char *) post_config_family, (char *) post_match_family) == 0;

    FcPatternDestroy(pattern);

    if (!family_names_match && !is_fallback) {
        FcPatternDestroy(match);
        return NULL;
    }

    return match;
}

// -----------------------------------------------------------------------------
// Check to see if the filename has already been assigned a fileid and, if so,
// use it. Otherwise, assign one. Return the resulting fileid.
// -----------------------------------------------------------------------------
static unsigned FileIdFromFilename(const char* filename)
{
    SkAutoMutexAcquire ac(global_fc_map_lock);

    std::map<std::string, unsigned>::const_iterator i =
        global_fc_map.find(filename);
    if (i == global_fc_map.end()) {
        const unsigned fileid = global_fc_map_next_id++;
        global_fc_map[filename] = fileid;
        global_fc_map_inverted[fileid] = filename;
        return fileid;
    } else {
        return i->second;
    }
}

SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace,
                                     const char familyName[],
                                     SkTypeface::Style style)
{
    const char* resolved_family_name = NULL;
    FcPattern* face_match = NULL;

    if (familyFace) {
        // Here we use the inverted global id map to find the filename from the
        // SkTypeface object. Given the filename we can ask fontconfig for the
        // familyname of the font.
        SkAutoMutexAcquire ac(global_fc_map_lock);

        const unsigned fileid = UniqueIdToFileId(familyFace->uniqueID());
        std::map<unsigned, std::string>::const_iterator i =
            global_fc_map_inverted.find(fileid);
        if (i == global_fc_map_inverted.end())
            return NULL;

        FcInit();
        face_match = FontMatch(false, FC_FILE, FcTypeString, i->second.c_str(),
                               NULL);

        if (!face_match)
            return NULL;
        FcChar8* family;
        if (FcPatternGetString(face_match, FC_FAMILY, 0, &family)) {
            FcPatternDestroy(face_match);
            return NULL;
        }
        // At this point, @family is pointing into the @face_match object so we
        // cannot release it yet.

        resolved_family_name = reinterpret_cast<char*>(family);
    } else if (familyName) {
        resolved_family_name = familyName;
    } else {
        return NULL;
    }

    {
        SkAutoMutexAcquire ac(global_fc_map_lock);
        FcInit();
    }

    // At this point, we have a resolved_family_name from somewhere
    SkASSERT(resolved_family_name);

    const int bold = style & SkTypeface::kBold ?
                     FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL;
    const int italic = style & SkTypeface::kItalic ?
                       FC_SLANT_ITALIC : FC_SLANT_ROMAN;
    FcPattern* match = FontMatch(false,
                                 FC_FAMILY, FcTypeString, resolved_family_name,
                                 FC_WEIGHT, FcTypeInteger, bold,
                                 FC_SLANT, FcTypeInteger, italic,
                                 NULL);
    if (face_match)
        FcPatternDestroy(face_match);

    if (!match)
        return NULL;

    FcChar8* filename;
    if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) {
        FcPatternDestroy(match);
        return NULL;
    }
    // Now @filename is pointing into @match

    const unsigned fileid = FileIdFromFilename(reinterpret_cast<char*>(filename));
    const unsigned id = FileIdAndStyleToUniqueId(fileid, style);
    SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id));
    FcPatternDestroy(match);
    return typeface;
}

SkTypeface* SkFontHost::ResolveTypeface(uint32_t id)
{
    SkAutoMutexAcquire ac(global_fc_map_lock);
    const SkTypeface::Style style = UniqueIdToStyle(id);
    const unsigned fileid = UniqueIdToFileId(id);

    std::map<unsigned, std::string>::const_iterator i =
        global_fc_map_inverted.find(fileid);
    if (i == global_fc_map_inverted.end())
        return NULL;

    return SkNEW_ARGS(FontConfigTypeface, (style, id));
}

SkStream* SkFontHost::OpenStream(uint32_t id)
{
    SkAutoMutexAcquire ac(global_fc_map_lock);
    const unsigned fileid = UniqueIdToFileId(id);

    std::map<unsigned, std::string>::const_iterator i =
        global_fc_map_inverted.find(fileid);
    if (i == global_fc_map_inverted.end())
        return NULL;

    return SkNEW_ARGS(SkFILEStream, (i->second.c_str()));
}

void SkFontHost::CloseStream(uint32_t fontID, SkStream* stream)
{
}

SkTypeface* SkFontHost::CreateTypeface(SkStream* stream)
{
    SkASSERT(!"SkFontHost::CreateTypeface unimplemented");
    return NULL;
}

SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
    SkASSERT(!"SkFontHost::Deserialize unimplemented");
    return NULL;
}

void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
    SkASSERT(!"SkFontHost::Serialize unimplemented");
}

SkScalerContext* SkFontHost::CreateFallbackScalerContext
        (const SkScalerContext::Rec& rec) {
    FcPattern* match = FontMatch(true, FC_FAMILY, FcTypeString, "serif",
                                 NULL);

    // This will fail when we have no fonts on the system.
    SkASSERT(match);

    FcChar8* filename;
    if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) {
        FcPatternDestroy(match);
        return NULL;
    }
    // Now @filename is pointing into @match

    const unsigned id = FileIdFromFilename(reinterpret_cast<char*>(filename));
    FcPatternDestroy(match);

    SkAutoDescriptor    ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
    SkDescriptor*       desc = ad.getDesc();

    desc->init();
    SkScalerContext::Rec* newRec =
        (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
                                              sizeof(rec), &rec);
    newRec->fFontID = id;
    desc->computeChecksum();

    return SkFontHost::CreateScalerContext(desc);
}

///////////////////////////////////////////////////////////////////////////////

size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar)
{
    if (sizeAllocatedSoFar > kFontCacheMemoryBudget)
        return sizeAllocatedSoFar - kFontCacheMemoryBudget;
    else
        return 0;   // nothing to do
}
<commit_msg>Linux: change Skia's fontconfig code to cache SkTypeface objects.<commit_after>/* libs/graphics/ports/SkFontHost_fontconfig.cpp
**
** Copyright 2008, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

// -----------------------------------------------------------------------------
// This file provides implementations of the font resolution members of
// SkFontHost by using the fontconfig[1] library. Fontconfig is usually found
// on Linux systems and handles configuration, parsing and caching issues
// involved with enumerating and matching fonts.
//
// [1] http://fontconfig.org
// -----------------------------------------------------------------------------

#include <map>
#include <string>

#include <fontconfig/fontconfig.h>

#include "SkDescriptor.h"
#include "SkFontHost.h"
#include "SkMMapStream.h"
#include "SkPaint.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkThread.h"
#include "SkTSearch.h"

// This is an extern from SkFontHost_FreeType
SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);

// -----------------------------------------------------------------------------
// The rest of Skia requires that fonts be identified by a unique unsigned id
// and that we be able to load them given the id. What we actually get from
// fontconfig is the filename of the font so we keep a locked map from
// filenames to fileid numbers and back.
//
// Note that there's also a unique id in the SkTypeface. This is unique over
// both filename and style. Thus we encode that id as (fileid << 8) | style.
// Although truetype fonts can support multiple faces in a single file, at the
// moment Skia doesn't.
// -----------------------------------------------------------------------------
static SkMutex global_fc_map_lock;
static std::map<std::string, unsigned> global_fc_map;
static std::map<unsigned, std::string> global_fc_map_inverted;
static std::map<uint32_t, SkTypeface *> global_fc_typefaces;
static unsigned global_fc_map_next_id = 0;

// This is the maximum size of the font cache.
static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024;  // 2MB

static unsigned UniqueIdToFileId(unsigned uniqueid)
{
    return uniqueid >> 8;
}

static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid)
{
    return static_cast<SkTypeface::Style>(uniqueid & 0xff);
}

static unsigned FileIdAndStyleToUniqueId(unsigned fileid,
                                         SkTypeface::Style style)
{
    // TODO(agl/brettw) bug 6291: This assertion fails for unknown reasons
    // on ChromeFontTest.LoadArial. This should be fixed.
    //SkASSERT(style & 0xff == style);
    return (fileid << 8) | static_cast<int>(style);
}

class FontConfigTypeface : public SkTypeface {
public:
    FontConfigTypeface(Style style, uint32_t id)
        : SkTypeface(style, id)
    { }
};

// -----------------------------------------------------------------------------
// Find a matching font where @type (one of FC_*) is equal to @value. For a
// list of types, see http://fontconfig.org/fontconfig-devel/x19.html#AEN27.
// The variable arguments are a list of triples, just like the first three
// arguments, and must be NULL terminated.
//
// For example, FontMatchString(FC_FILE, FcTypeString,
//                              "/usr/share/fonts/myfont.ttf", NULL);
// -----------------------------------------------------------------------------
static FcPattern* FontMatch(bool is_fallback,
                            const char* type, FcType vtype, const void* value,
                            ...)
{
    va_list ap;
    va_start(ap, value);

    FcPattern* pattern = FcPatternCreate();
    bool family_requested = false;

    for (;;) {
        FcValue fcvalue;
        fcvalue.type = vtype;
        switch (vtype) {
            case FcTypeString:
                fcvalue.u.s = (FcChar8*) value;
                break;
            case FcTypeInteger:
                fcvalue.u.i = (int) value;
                break;
            default:
                SkASSERT(!"FontMatch unhandled type");
        }
        FcPatternAdd(pattern, type, fcvalue, 0);

        if (vtype == FcTypeString && strcmp(type, FC_FAMILY) == 0)
            family_requested = true;

        type = va_arg(ap, const char *);
        if (!type)
            break;
        // FcType is promoted to int when passed through ...
        vtype = static_cast<FcType>(va_arg(ap, int));
        value = va_arg(ap, const void *);
    };
    va_end(ap);

    FcConfigSubstitute(0, pattern, FcMatchPattern);
    FcDefaultSubstitute(pattern);

    // Font matching:
    // CSS often specifies a fallback list of families:
    //    font-family: a, b, c, serif;
    // However, fontconfig will always do its best to find *a* font when asked
    // for something so we need a way to tell if the match which it has found is
    // "good enough" for us. Otherwise, we can return NULL which gets piped up
    // and lets WebKit know to try the next CSS family name. However, fontconfig
    // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
    // wish to support that.
    //
    // Thus, if a specific family is requested we set @family_requested. Then we
    // record two strings: the family name after config processing and the
    // family name after resolving. If the two are equal, it's a good match.
    //
    // So consider the case where a user has mapped Arial to Helvetica in their
    // config.
    //    requested family: "Arial"
    //    post_config_family: "Helvetica"
    //    post_match_family: "Helvetica"
    //      -> good match
    //
    // and for a missing font:
    //    requested family: "Monaco"
    //    post_config_family: "Monaco"
    //    post_match_family: "Times New Roman"
    //      -> BAD match
    FcChar8* post_config_family;
    FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family);

    FcResult result;
    FcPattern* match = FcFontMatch(0, pattern, &result);
    if (!match) {
        FcPatternDestroy(pattern);
        return NULL;
    }

    FcChar8* post_match_family;
    FcPatternGetString(match, FC_FAMILY, 0, &post_match_family);
    const bool family_names_match =
        !family_requested ?
        true :
        strcasecmp((char *) post_config_family, (char *) post_match_family) == 0;

    FcPatternDestroy(pattern);

    if (!family_names_match && !is_fallback) {
        FcPatternDestroy(match);
        return NULL;
    }

    return match;
}

// -----------------------------------------------------------------------------
// Check to see if the filename has already been assigned a fileid and, if so,
// use it. Otherwise, assign one. Return the resulting fileid.
// -----------------------------------------------------------------------------
static unsigned FileIdFromFilename(const char* filename)
{
    SkAutoMutexAcquire ac(global_fc_map_lock);

    std::map<std::string, unsigned>::const_iterator i =
        global_fc_map.find(filename);
    if (i == global_fc_map.end()) {
        const unsigned fileid = global_fc_map_next_id++;
        global_fc_map[filename] = fileid;
        global_fc_map_inverted[fileid] = filename;
        return fileid;
    } else {
        return i->second;
    }
}

SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace,
                                     const char familyName[],
                                     SkTypeface::Style style)
{
    const char* resolved_family_name = NULL;
    FcPattern* face_match = NULL;

    if (familyFace) {
        // Here we use the inverted global id map to find the filename from the
        // SkTypeface object. Given the filename we can ask fontconfig for the
        // familyname of the font.
        SkAutoMutexAcquire ac(global_fc_map_lock);

        const unsigned fileid = UniqueIdToFileId(familyFace->uniqueID());
        std::map<unsigned, std::string>::const_iterator i =
            global_fc_map_inverted.find(fileid);
        if (i == global_fc_map_inverted.end())
            return NULL;

        FcInit();
        face_match = FontMatch(false, FC_FILE, FcTypeString, i->second.c_str(),
                               NULL);

        if (!face_match)
            return NULL;
        FcChar8* family;
        if (FcPatternGetString(face_match, FC_FAMILY, 0, &family)) {
            FcPatternDestroy(face_match);
            return NULL;
        }
        // At this point, @family is pointing into the @face_match object so we
        // cannot release it yet.

        resolved_family_name = reinterpret_cast<char*>(family);
    } else if (familyName) {
        resolved_family_name = familyName;
    } else {
        return NULL;
    }

    {
        SkAutoMutexAcquire ac(global_fc_map_lock);
        FcInit();
    }

    // At this point, we have a resolved_family_name from somewhere
    SkASSERT(resolved_family_name);

    const int bold = style & SkTypeface::kBold ?
                     FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL;
    const int italic = style & SkTypeface::kItalic ?
                       FC_SLANT_ITALIC : FC_SLANT_ROMAN;
    FcPattern* match = FontMatch(false,
                                 FC_FAMILY, FcTypeString, resolved_family_name,
                                 FC_WEIGHT, FcTypeInteger, bold,
                                 FC_SLANT, FcTypeInteger, italic,
                                 NULL);
    if (face_match)
        FcPatternDestroy(face_match);

    if (!match)
        return NULL;

    FcChar8* filename;
    if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) {
        FcPatternDestroy(match);
        return NULL;
    }
    // Now @filename is pointing into @match

    const unsigned fileid = FileIdFromFilename(reinterpret_cast<char*>(filename));
    const unsigned id = FileIdAndStyleToUniqueId(fileid, style);
    SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id));
    FcPatternDestroy(match);

    {
        SkAutoMutexAcquire ac(global_fc_map_lock);
        global_fc_typefaces[id] = typeface;
    }

    return typeface;
}

SkTypeface* SkFontHost::ResolveTypeface(uint32_t id)
{
    SkAutoMutexAcquire ac(global_fc_map_lock);
    const std::map<uint32_t, SkTypeface *>::iterator
      i = global_fc_typefaces.find(id);

    if (i == global_fc_typefaces.end())
        return NULL;
    return i->second;
}

SkStream* SkFontHost::OpenStream(uint32_t id)
{
    SkAutoMutexAcquire ac(global_fc_map_lock);
    const unsigned fileid = UniqueIdToFileId(id);

    std::map<unsigned, std::string>::const_iterator i =
        global_fc_map_inverted.find(fileid);
    if (i == global_fc_map_inverted.end())
        return NULL;

    return SkNEW_ARGS(SkFILEStream, (i->second.c_str()));
}

void SkFontHost::CloseStream(uint32_t fontID, SkStream* stream)
{
}

SkTypeface* SkFontHost::CreateTypeface(SkStream* stream)
{
    SkASSERT(!"SkFontHost::CreateTypeface unimplemented");
    return NULL;
}

SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
    SkASSERT(!"SkFontHost::Deserialize unimplemented");
    return NULL;
}

void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
    SkASSERT(!"SkFontHost::Serialize unimplemented");
}

SkScalerContext* SkFontHost::CreateFallbackScalerContext
        (const SkScalerContext::Rec& rec) {
    FcPattern* match = FontMatch(true, FC_FAMILY, FcTypeString, "serif",
                                 NULL);

    // This will fail when we have no fonts on the system.
    SkASSERT(match);

    FcChar8* filename;
    if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) {
        FcPatternDestroy(match);
        return NULL;
    }
    // Now @filename is pointing into @match

    const unsigned id = FileIdFromFilename(reinterpret_cast<char*>(filename));
    FcPatternDestroy(match);

    SkAutoDescriptor    ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
    SkDescriptor*       desc = ad.getDesc();

    desc->init();
    SkScalerContext::Rec* newRec =
        (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
                                              sizeof(rec), &rec);
    newRec->fFontID = id;
    desc->computeChecksum();

    return SkFontHost::CreateScalerContext(desc);
}

///////////////////////////////////////////////////////////////////////////////

size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar)
{
    if (sizeAllocatedSoFar > kFontCacheMemoryBudget)
        return sizeAllocatedSoFar - kFontCacheMemoryBudget;
    else
        return 0;   // nothing to do
}
<|endoftext|>


<commit_before><commit_msg>Optimize the query for loading the recipe list and put uncategorized recipes in their own category.  This may cause so odd behavior as I'm still in the progress of completing things, so watch out.<commit_after><|endoftext|>


<commit_before>/*
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.

    ---
    file: docwordcompletion.cpp

    KTextEditor plugin to autocompletion with document words.
    Copyright Anders Lund <anders.lund@lund.tdcadsl.dk>, 2003

    The following completion methods are supported:
    * Completion with bigger matching words in
      either direction (backward/forward).
    * NOT YET Pop up a list of all bigger matching words in document

*/
//BEGIN includes
#include "docwordcompletion.h"

#include <ktexteditor/document.h>
#include <ktexteditor/viewcursorinterface.h>
#include <ktexteditor/editinterface.h>
#include <ktexteditor/variableinterface.h>

#include <kapplication.h>
#include <kconfig.h>
#include <kdialog.h>
#include <kgenericfactory.h>
#include <klocale.h>
#include <kaction.h>
#include <knotifyclient.h>
#include <kparts/part.h>
#include <kiconloader.h>

#include <qregexp.h>
#include <qstring.h>
#include <qdict.h>
#include <qspinbox.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qhbox.h>
#include <qwhatsthis.h>
#include <qcheckbox.h>

// #include <kdebug.h>
//END

//BEGIN DocWordCompletionPlugin
K_EXPORT_COMPONENT_FACTORY( ktexteditor_docwordcompletion, KGenericFactory<DocWordCompletionPlugin>( "ktexteditor_docwordcompletion" ) );
DocWordCompletionPlugin::DocWordCompletionPlugin( QObject *parent,
                            const char* name,
                            const QStringList& /*args*/ )
	: KTextEditor::Plugin ( (KTextEditor::Document*) parent, name )
{
  readConfig();
}

void DocWordCompletionPlugin::readConfig()
{
  KConfig *config = kapp->config();
  config->setGroup( "DocWordCompletion Plugin" );
  m_treshold = config->readNumEntry( "treshold", 3 );
  m_autopopup = config->readBoolEntry( "autopopup", true );
}

void DocWordCompletionPlugin::writeConfig()
{
  KConfig *config = kapp->config();
  config->setGroup("DocWordCompletion Plugin");
  config->writeEntry("autopopup", m_autopopup );
  config->writeEntry("treshold", m_treshold );
}

void DocWordCompletionPlugin::addView(KTextEditor::View *view)
{
  DocWordCompletionPluginView *nview = new DocWordCompletionPluginView (m_treshold, m_autopopup, view, "Document word completion");
  m_views.append (nview);
}

void DocWordCompletionPlugin::removeView(KTextEditor::View *view)
{
  for (uint z=0; z < m_views.count(); z++)
    if (m_views.at(z)->parentClient() == view)
    {
       DocWordCompletionPluginView *nview = m_views.at(z);
       m_views.remove (nview);
       delete nview;
    }
}

KTextEditor::ConfigPage* DocWordCompletionPlugin::configPage( uint, QWidget *parent, const char *name )
{
  return new DocWordCompletionConfigPage( this, parent, name );
}

QString DocWordCompletionPlugin::configPageName( uint ) const
{
  return i18n("Word Completion Plugin");
}

QString DocWordCompletionPlugin::configPageFullName( uint ) const
{
  return i18n("Configure the Word Completion Plugin");
}

// FIXME provide sucn a icon
       QPixmap DocWordCompletionPlugin::configPagePixmap( uint, int size ) const
{
  return UserIcon( "kte_wordcompletion", size );
}
//END

//BEGIN DocWordCompletionPluginView
struct DocWordCompletionPluginViewPrivate
{
  uint line, col;       // start position of last match (where to search from)
  uint cline, ccol;     // cursor position
  uint lilen;           // length of last insertion
  QString last;         // last word we were trying to match
  QString lastIns;      // latest applied completion
  QRegExp re;           // hrm
  KToggleAction *autopopup; // for accessing state
  uint treshold;         // the required length of a word before popping up the completion list automatically
};

DocWordCompletionPluginView::DocWordCompletionPluginView( uint treshold, bool autopopup, KTextEditor::View *view, const char *name )
  : QObject( view, name ),
    KXMLGUIClient( view ),
    m_view( view ),
    d( new DocWordCompletionPluginViewPrivate )
{
  d->treshold = treshold;
  view->insertChildClient( this );
  setInstance( KGenericFactory<DocWordCompletionPlugin>::instance() );

  (void) new KAction( i18n("Reuse Word Behind"), CTRL+Key_H, this,
    SLOT(completeBackwards()), actionCollection(), "doccomplete_bw" );
  (void) new KAction( i18n("Reuse Word Ahead"), CTRL+Key_J, this,
    SLOT(completeForwards()), actionCollection(), "doccomplete_fw" );
  (void) new KAction( i18n("Pop Up Completion List"), CTRL+Key_Y, this,
    SLOT(popupCompletionList()), actionCollection(), "doccomplete_pu" );
  d->autopopup = new KToggleAction( i18n("Automatic Completion Popup"), 0, this,
    SLOT(toggleAutoPopup()), actionCollection(), "enable_autopopup" );

  d->autopopup->setChecked( autopopup );
  toggleAutoPopup();

  setXMLFile("docwordcompletionui.rc");

  KTextEditor::VariableInterface *vi = KTextEditor::variableInterface( view->document() );
  if ( vi )
  {
    QString e = vi->variable("wordcompletion-autopopup");
    if ( ! e.isEmpty() )
      d->autopopup->setEnabled( e == "true" );

    connect( view->document(), SIGNAL(variableChanged(const QString &, const QString &)),
             this, SLOT(slotVariableChanged(const QString &, const QString &)) );
  }
}

void DocWordCompletionPluginView::settreshold( uint t )
{
  d->treshold = t;
}

void DocWordCompletionPluginView::completeBackwards()
{
  complete( false );
}

void DocWordCompletionPluginView::completeForwards()
{
  complete();
}

// Pop up the editors completion list if applicable
void DocWordCompletionPluginView::popupCompletionList( QString w )
{
  if ( w.isEmpty() )
    w = word();
  if ( w.isEmpty() )
    return;

  KTextEditor::CodeCompletionInterface *cci = codeCompletionInterface( m_view );
  cci->showCompletionBox( allMatches( w ), w.length() );
}

void DocWordCompletionPluginView::toggleAutoPopup()
{
  if ( d->autopopup->isChecked() )
    connect( m_view->document(), SIGNAL(textChanged()), this, SLOT(autoPopupCompletionList()) );
  else
    disconnect( m_view->document(), SIGNAL(textChanged()), this, SLOT(autoPopupCompletionList()) );
}

// for autopopup FIXME - don't pop up if reuse word is inserting
void DocWordCompletionPluginView::autoPopupCompletionList()
{
  QString w = word();
  if ( w.length() == d->treshold )
  {
      popupCompletionList( w );
  }
}

// Do one completion, searching in the desired direction,
// if possible
void DocWordCompletionPluginView::complete( bool fw )
{
  // setup
  KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() );
  // find the word we are typing
  uint cline, ccol;
  viewCursorInterface( m_view )->cursorPosition( &cline, &ccol );
  QString wrd = word();
  if ( wrd.isEmpty() ) return;

  /* IF the current line is equal to the previous line
     AND the position - the length of the last inserted string
          is equal to the old position
     AND the lastinsertedlength last characters of the word is
          equal to the last inserted string
          */
  if ( cline == d-> cline &&
          ccol - d->lilen == d->ccol &&
          wrd.endsWith( d->lastIns ) )
  {
    // this is a repeted activation
    ccol = d->ccol;
    wrd = d->last;
  }
  else
  {
    d->cline = cline;
    d->ccol = ccol;
    d->last = wrd;
    d->lastIns = QString::null;
    d->line = d->cline;
    d->col = d->ccol - wrd.length();
    d->lilen = 0;
  }

  d->re.setPattern( "\\b" + wrd + "(\\w+)" );
  int inc = fw ? 1 : -1;
  int pos ( 0 );
  QString ln = ei->textLine( d->line );

  if ( ! fw )
    ln = ln.mid( 0, d->col );

  while ( true )
  {
    pos = fw ?
      d->re.search( ln, d->col ) :
      d->re.searchRev( ln, d->col );

    if ( pos > -1 ) // we matched a word
    {
      QString m = d->re.cap( 1 );
      if ( m != d->lastIns )
      {
        // we got good a match! replace text and return.
        if ( d->lilen )
          ei->removeText( d->cline, d->ccol, d->cline, d->ccol + d->lilen );
        ei->insertText( d->cline, d->ccol, m );

        d->lastIns = m;
        d->lilen = m.length();
        d->col = pos; // for next try

        if ( fw )
          d->col += m.length();

        return;
      }

      // equal to last one, continue
      else
      {
        d->col = pos; // for next try
        if ( fw )
          d->col += m.length();
        else // FIXME figure out if all of that is really nessecary
        {
          if ( pos == 0 )
          {
            if ( d->line > 0 )
            {
              d->line += inc;
              ln = ei->textLine( d->line );
              d->col = ln.length();
            }
            else
            {
              KNotifyClient::beep();
              return;
            }
          }
          else
            d->col--;
        }
      }
    }

    else  // no match
    {
      if ( ! fw && d->line == 0)
      {
        KNotifyClient::beep();
        return;
      }
      else if ( fw && d->line >= ei->numLines() )
      {
        KNotifyClient::beep();
        return;
      }

      d->line += inc;
      if ( fw )
        d->col++;

      ln = ei->textLine( d->line );
      d->col = fw ? 0 : ln.length();
    }
  } // while true
}

// Return the string to complete (the letters behind the cursor)
QString DocWordCompletionPluginView::word()
{
  uint cline, ccol;
  viewCursorInterface( m_view )->cursorPositionReal( &cline, &ccol );
  if ( ! ccol ) return QString::null; // no word
  KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() );
  d->re.setPattern( "\\b(\\w+)$" );
  if ( d->re.searchRev(
        ei->text( cline, 0, cline, ccol )
        ) < 0 )
    return QString::null; // no word
  return d->re.cap( 1 );
}

// Scan throught the entire document for possible completions,
// ignoring any dublets
QValueList<KTextEditor::CompletionEntry> DocWordCompletionPluginView::allMatches( const QString &word )
{
  QValueList<KTextEditor::CompletionEntry> l;
  uint i( 0 );
  int pos( 0 );
  d->re.setPattern( "\\b("+word+"\\w+)" );
  QString s, m;
  KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() );
  QDict<int> seen; // maybe slow with > 17 matches
  int sawit(1);    // to ref for the dict

  while( i < ei->numLines() )
  {
    s = ei->textLine( i );
    pos = 0;
    while ( pos >= 0 )
    {
      pos = d->re.search( s, pos );
      if ( pos >= 0 )
      {
        m = d->re.cap( 1 );
        if ( ! seen[ m ] ) {
          seen.insert( m, &sawit );
          KTextEditor::CompletionEntry e;
          e.text = m;
          l.append( e );
        }
        pos += d->re.matchedLength();
      }
    }
    i++;
  }
  return l;
}

void DocWordCompletionPluginView::slotVariableChanged( const QString &var, const QString &val )
{
  if ( var == "wordcompletion-autopopup" )
    d->autopopup->setEnabled( val == "true" );
  else if ( var == "wordcompletion-treshold" )
    d->treshold = val.toInt();
}
//END

//BEGIN DocWordCompletionConfigPage
DocWordCompletionConfigPage::DocWordCompletionConfigPage( DocWordCompletionPlugin *completion, QWidget *parent, const char *name )
  : KTextEditor::ConfigPage( parent, name )
  , m_completion( completion )
{
  QVBoxLayout *lo = new QVBoxLayout( this );
  lo->setSpacing( KDialog::spacingHint() );

  cbAutoPopup = new QCheckBox( i18n("Automatically show completion list"), this );
  lo->addWidget( cbAutoPopup );

  QHBox *hb = new QHBox( this );
  hb->setSpacing( KDialog::spacingHint() );
  lo->addWidget( hb );
  new QLabel( i18n("when the word is"), hb );
  sbAutoPopup = new QSpinBox( 1, 30, 1, hb );
  new QLabel( i18n("characters long."), hb );

  QWhatsThis::add( cbAutoPopup, i18n(
      "Enable the automatic completion list popup as default. The popup can "
      "be disabled on a view basis from the 'Tools' menu.") );
  QWhatsThis::add( sbAutoPopup, i18n(
      "Define the length a word should have before the completion list "
      "is displayed.") );

  cbAutoPopup->setChecked( m_completion->autoPopupEnabled() );
  sbAutoPopup->setValue( m_completion->treshold() );

  lo->addStretch();
}

void DocWordCompletionConfigPage::apply()
{
  m_completion->setAutoPopupEnabled( cbAutoPopup->isChecked() );
  m_completion->setTreshold( sbAutoPopup->value() );
  m_completion->writeConfig();
}

void DocWordCompletionConfigPage::reset()
{
  cbAutoPopup->setChecked( m_completion->autoPopupEnabled() );
  sbAutoPopup->setValue( m_completion->treshold() );
}

void DocWordCompletionConfigPage::defaults()
{
  cbAutoPopup->setChecked( true );
  sbAutoPopup->setValue( 3 );
}

//END DocWordCompletionConfigPage

#include "docwordcompletion.moc"
<commit_msg>don't show the completion box in kate, if characters are inserted/removed eg by the comment/uncomment feature<commit_after>/*
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.

    ---
    file: docwordcompletion.cpp

    KTextEditor plugin to autocompletion with document words.
    Copyright Anders Lund <anders.lund@lund.tdcadsl.dk>, 2003

    The following completion methods are supported:
    * Completion with bigger matching words in
      either direction (backward/forward).
    * NOT YET Pop up a list of all bigger matching words in document

*/
//BEGIN includes
#include "docwordcompletion.h"

#include <ktexteditor/document.h>
#include <ktexteditor/viewcursorinterface.h>
#include <ktexteditor/editinterface.h>
#include <ktexteditor/variableinterface.h>

#include <kapplication.h>
#include <kconfig.h>
#include <kdialog.h>
#include <kgenericfactory.h>
#include <klocale.h>
#include <kaction.h>
#include <knotifyclient.h>
#include <kparts/part.h>
#include <kiconloader.h>

#include <qregexp.h>
#include <qstring.h>
#include <qdict.h>
#include <qspinbox.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qhbox.h>
#include <qwhatsthis.h>
#include <qcheckbox.h>

// #include <kdebug.h>
//END

//BEGIN DocWordCompletionPlugin
K_EXPORT_COMPONENT_FACTORY( ktexteditor_docwordcompletion, KGenericFactory<DocWordCompletionPlugin>( "ktexteditor_docwordcompletion" ) );
DocWordCompletionPlugin::DocWordCompletionPlugin( QObject *parent,
                            const char* name,
                            const QStringList& /*args*/ )
	: KTextEditor::Plugin ( (KTextEditor::Document*) parent, name )
{
  readConfig();
}

void DocWordCompletionPlugin::readConfig()
{
  KConfig *config = kapp->config();
  config->setGroup( "DocWordCompletion Plugin" );
  m_treshold = config->readNumEntry( "treshold", 3 );
  m_autopopup = config->readBoolEntry( "autopopup", true );
}

void DocWordCompletionPlugin::writeConfig()
{
  KConfig *config = kapp->config();
  config->setGroup("DocWordCompletion Plugin");
  config->writeEntry("autopopup", m_autopopup );
  config->writeEntry("treshold", m_treshold );
}

void DocWordCompletionPlugin::addView(KTextEditor::View *view)
{
  DocWordCompletionPluginView *nview = new DocWordCompletionPluginView (m_treshold, m_autopopup, view, "Document word completion");
  m_views.append (nview);
}

void DocWordCompletionPlugin::removeView(KTextEditor::View *view)
{
  for (uint z=0; z < m_views.count(); z++)
    if (m_views.at(z)->parentClient() == view)
    {
       DocWordCompletionPluginView *nview = m_views.at(z);
       m_views.remove (nview);
       delete nview;
    }
}

KTextEditor::ConfigPage* DocWordCompletionPlugin::configPage( uint, QWidget *parent, const char *name )
{
  return new DocWordCompletionConfigPage( this, parent, name );
}

QString DocWordCompletionPlugin::configPageName( uint ) const
{
  return i18n("Word Completion Plugin");
}

QString DocWordCompletionPlugin::configPageFullName( uint ) const
{
  return i18n("Configure the Word Completion Plugin");
}

// FIXME provide sucn a icon
       QPixmap DocWordCompletionPlugin::configPagePixmap( uint, int size ) const
{
  return UserIcon( "kte_wordcompletion", size );
}
//END

//BEGIN DocWordCompletionPluginView
struct DocWordCompletionPluginViewPrivate
{
  uint line, col;       // start position of last match (where to search from)
  uint cline, ccol;     // cursor position
  uint lilen;           // length of last insertion
  QString last;         // last word we were trying to match
  QString lastIns;      // latest applied completion
  QRegExp re;           // hrm
  KToggleAction *autopopup; // for accessing state
  uint treshold;         // the required length of a word before popping up the completion list automatically
};

DocWordCompletionPluginView::DocWordCompletionPluginView( uint treshold, bool autopopup, KTextEditor::View *view, const char *name )
  : QObject( view, name ),
    KXMLGUIClient( view ),
    m_view( view ),
    d( new DocWordCompletionPluginViewPrivate )
{
  d->treshold = treshold;
  view->insertChildClient( this );
  setInstance( KGenericFactory<DocWordCompletionPlugin>::instance() );

  (void) new KAction( i18n("Reuse Word Behind"), CTRL+Key_H, this,
    SLOT(completeBackwards()), actionCollection(), "doccomplete_bw" );
  (void) new KAction( i18n("Reuse Word Ahead"), CTRL+Key_J, this,
    SLOT(completeForwards()), actionCollection(), "doccomplete_fw" );
  (void) new KAction( i18n("Pop Up Completion List"), CTRL+Key_Y, this,
    SLOT(popupCompletionList()), actionCollection(), "doccomplete_pu" );
  d->autopopup = new KToggleAction( i18n("Automatic Completion Popup"), 0, this,
    SLOT(toggleAutoPopup()), actionCollection(), "enable_autopopup" );

  d->autopopup->setChecked( autopopup );
  toggleAutoPopup();

  setXMLFile("docwordcompletionui.rc");

  KTextEditor::VariableInterface *vi = KTextEditor::variableInterface( view->document() );
  if ( vi )
  {
    QString e = vi->variable("wordcompletion-autopopup");
    if ( ! e.isEmpty() )
      d->autopopup->setEnabled( e == "true" );

    connect( view->document(), SIGNAL(variableChanged(const QString &, const QString &)),
             this, SLOT(slotVariableChanged(const QString &, const QString &)) );
  }
}

void DocWordCompletionPluginView::settreshold( uint t )
{
  d->treshold = t;
}

void DocWordCompletionPluginView::completeBackwards()
{
  complete( false );
}

void DocWordCompletionPluginView::completeForwards()
{
  complete();
}

// Pop up the editors completion list if applicable
void DocWordCompletionPluginView::popupCompletionList( QString w )
{
  if ( w.isEmpty() )
    w = word();
  if ( w.isEmpty() )
    return;

  KTextEditor::CodeCompletionInterface *cci = codeCompletionInterface( m_view );
  cci->showCompletionBox( allMatches( w ), w.length() );
}

void DocWordCompletionPluginView::toggleAutoPopup()
{
  if ( d->autopopup->isChecked() ) {
    if (!  connect( m_view->document(), SIGNAL(charactersInteractivelyInserted(int ,int ,const QString&)), this, SLOT(autoPopupCompletionList()) ))
    connect( m_view->document(), SIGNAL(textChanged()), this, SLOT(autoPopupCompletionList()) );
  } else {
    disconnect( m_view->document(), SIGNAL(textChanged()), this, SLOT(autoPopupCompletionList()) );
    disconnect( m_view->document(), SIGNAL(charactersInteractivelyInserted(int ,int ,const QString&)), this, SLOT(autoPopupCompletionList()) );

  }
}

// for autopopup FIXME - don't pop up if reuse word is inserting
void DocWordCompletionPluginView::autoPopupCompletionList()
{
  QString w = word();
  if ( w.length() == d->treshold )
  {
      popupCompletionList( w );
  }
}

// Do one completion, searching in the desired direction,
// if possible
void DocWordCompletionPluginView::complete( bool fw )
{
  // setup
  KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() );
  // find the word we are typing
  uint cline, ccol;
  viewCursorInterface( m_view )->cursorPosition( &cline, &ccol );
  QString wrd = word();
  if ( wrd.isEmpty() ) return;

  /* IF the current line is equal to the previous line
     AND the position - the length of the last inserted string
          is equal to the old position
     AND the lastinsertedlength last characters of the word is
          equal to the last inserted string
          */
  if ( cline == d-> cline &&
          ccol - d->lilen == d->ccol &&
          wrd.endsWith( d->lastIns ) )
  {
    // this is a repeted activation
    ccol = d->ccol;
    wrd = d->last;
  }
  else
  {
    d->cline = cline;
    d->ccol = ccol;
    d->last = wrd;
    d->lastIns = QString::null;
    d->line = d->cline;
    d->col = d->ccol - wrd.length();
    d->lilen = 0;
  }

  d->re.setPattern( "\\b" + wrd + "(\\w+)" );
  int inc = fw ? 1 : -1;
  int pos ( 0 );
  QString ln = ei->textLine( d->line );

  if ( ! fw )
    ln = ln.mid( 0, d->col );

  while ( true )
  {
    pos = fw ?
      d->re.search( ln, d->col ) :
      d->re.searchRev( ln, d->col );

    if ( pos > -1 ) // we matched a word
    {
      QString m = d->re.cap( 1 );
      if ( m != d->lastIns )
      {
        // we got good a match! replace text and return.
        if ( d->lilen )
          ei->removeText( d->cline, d->ccol, d->cline, d->ccol + d->lilen );
        ei->insertText( d->cline, d->ccol, m );

        d->lastIns = m;
        d->lilen = m.length();
        d->col = pos; // for next try

        if ( fw )
          d->col += m.length();

        return;
      }

      // equal to last one, continue
      else
      {
        d->col = pos; // for next try
        if ( fw )
          d->col += m.length();
        else // FIXME figure out if all of that is really nessecary
        {
          if ( pos == 0 )
          {
            if ( d->line > 0 )
            {
              d->line += inc;
              ln = ei->textLine( d->line );
              d->col = ln.length();
            }
            else
            {
              KNotifyClient::beep();
              return;
            }
          }
          else
            d->col--;
        }
      }
    }

    else  // no match
    {
      if ( ! fw && d->line == 0)
      {
        KNotifyClient::beep();
        return;
      }
      else if ( fw && d->line >= ei->numLines() )
      {
        KNotifyClient::beep();
        return;
      }

      d->line += inc;
      if ( fw )
        d->col++;

      ln = ei->textLine( d->line );
      d->col = fw ? 0 : ln.length();
    }
  } // while true
}

// Return the string to complete (the letters behind the cursor)
QString DocWordCompletionPluginView::word()
{
  uint cline, ccol;
  viewCursorInterface( m_view )->cursorPositionReal( &cline, &ccol );
  if ( ! ccol ) return QString::null; // no word
  KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() );
  d->re.setPattern( "\\b(\\w+)$" );
  if ( d->re.searchRev(
        ei->text( cline, 0, cline, ccol )
        ) < 0 )
    return QString::null; // no word
  return d->re.cap( 1 );
}

// Scan throught the entire document for possible completions,
// ignoring any dublets
QValueList<KTextEditor::CompletionEntry> DocWordCompletionPluginView::allMatches( const QString &word )
{
  QValueList<KTextEditor::CompletionEntry> l;
  uint i( 0 );
  int pos( 0 );
  d->re.setPattern( "\\b("+word+"\\w+)" );
  QString s, m;
  KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() );
  QDict<int> seen; // maybe slow with > 17 matches
  int sawit(1);    // to ref for the dict

  while( i < ei->numLines() )
  {
    s = ei->textLine( i );
    pos = 0;
    while ( pos >= 0 )
    {
      pos = d->re.search( s, pos );
      if ( pos >= 0 )
      {
        m = d->re.cap( 1 );
        if ( ! seen[ m ] ) {
          seen.insert( m, &sawit );
          KTextEditor::CompletionEntry e;
          e.text = m;
          l.append( e );
        }
        pos += d->re.matchedLength();
      }
    }
    i++;
  }
  return l;
}

void DocWordCompletionPluginView::slotVariableChanged( const QString &var, const QString &val )
{
  if ( var == "wordcompletion-autopopup" )
    d->autopopup->setEnabled( val == "true" );
  else if ( var == "wordcompletion-treshold" )
    d->treshold = val.toInt();
}
//END

//BEGIN DocWordCompletionConfigPage
DocWordCompletionConfigPage::DocWordCompletionConfigPage( DocWordCompletionPlugin *completion, QWidget *parent, const char *name )
  : KTextEditor::ConfigPage( parent, name )
  , m_completion( completion )
{
  QVBoxLayout *lo = new QVBoxLayout( this );
  lo->setSpacing( KDialog::spacingHint() );

  cbAutoPopup = new QCheckBox( i18n("Automatically show completion list"), this );
  lo->addWidget( cbAutoPopup );

  QHBox *hb = new QHBox( this );
  hb->setSpacing( KDialog::spacingHint() );
  lo->addWidget( hb );
  new QLabel( i18n("when the word is"), hb );
  sbAutoPopup = new QSpinBox( 1, 30, 1, hb );
  new QLabel( i18n("characters long."), hb );

  QWhatsThis::add( cbAutoPopup, i18n(
      "Enable the automatic completion list popup as default. The popup can "
      "be disabled on a view basis from the 'Tools' menu.") );
  QWhatsThis::add( sbAutoPopup, i18n(
      "Define the length a word should have before the completion list "
      "is displayed.") );

  cbAutoPopup->setChecked( m_completion->autoPopupEnabled() );
  sbAutoPopup->setValue( m_completion->treshold() );

  lo->addStretch();
}

void DocWordCompletionConfigPage::apply()
{
  m_completion->setAutoPopupEnabled( cbAutoPopup->isChecked() );
  m_completion->setTreshold( sbAutoPopup->value() );
  m_completion->writeConfig();
}

void DocWordCompletionConfigPage::reset()
{
  cbAutoPopup->setChecked( m_completion->autoPopupEnabled() );
  sbAutoPopup->setValue( m_completion->treshold() );
}

void DocWordCompletionConfigPage::defaults()
{
  cbAutoPopup->setChecked( true );
  sbAutoPopup->setValue( 3 );
}

//END DocWordCompletionConfigPage

#include "docwordcompletion.moc"
<|endoftext|>


<commit_before>#ifndef DUNE_DETAILED_DISCRETIZATIONS_SPACE_INTERFACE_HH
#define DUNE_DETAILED_DISCRETIZATIONS_SPACE_INTERFACE_HH

#include <dune/common/bartonnackmanifcheck.hh>
#include <dune/common/dynvector.hh>

#include <dune/stuff/la/container/pattern.hh>

namespace Dune {
namespace Detailed {
namespace Discretizations {

template <class Traits>
class SpaceInterface
{
public:
  typedef typename Traits::derived_type derived_type;

  typedef typename Traits::GridPartType GridPartType;
  static const int polOrder = Traits::polOrder;
  typedef typename GridPartType::ctype DomainFieldType;
  static const unsigned int dimDomain = GridPartType::dimension;
  typedef typename Traits::RangeFieldType RangeFieldType;
  static const unsigned int dimRangeRows = Traits::dimRangeRows;
  static const unsigned int dimRangeCols = Traits::dimRangeCols;

  typedef typename Traits::BackendType BackendType;
  typedef typename Traits::MapperType MapperType;
  typedef typename Traits::BaseFunctionSetType BaseFunctionSetType;
  typedef typename Traits::EntityType EntityType;

  typedef Dune::Stuff::LA::Container::SparsityPatternDefault PatternType;

  const GridPartType& gridPart() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().gridPart());
    return asImp().gridPart();
  }

  const BackendType& backend() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().backend());
    return asImp().backend();
  }

  bool continuous() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().continuous());
    return asImp().continuous();
  }

  const MapperType& mapper() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().mapper());
    return asImp().mapper();
  }

  BaseFunctionSetType baseFunctionSet(const EntityType& entity) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().baseFunctionSet(entity));
    return asImp().baseFunctionSet(entity);
  }

  PatternType* computePattern() const
  {
    return computePattern(*this);
  }

  template <class OtherSpaceType>
  PatternType* computePattern(const OtherSpaceType& other) const
  {
    // check type of the other space
    return computePattern(gridPart(), other);
  }

  /**
   *  \brief  computes a sparsity pattern, where this space is the test space (rows/outer) and the other space is the
   *          ansatz space (cols/inner)
   */
  template <class LocalGridPartType, class O>
  PatternType* computePattern(const LocalGridPartType& localGridPart, const SpaceInterface<O>& otherSpace) const
  {
    typedef typename PatternType::size_type size_type;
    PatternType* ret     = new PatternType(mapper().size());
    PatternType& pattern = *ret;
    // walk the grid part
    for (typename LocalGridPartType::template Codim<0>::IteratorType entityIt = localGridPart.template begin<0>();
         entityIt != localGridPart.template end<0>();
         ++entityIt) {
      const typename LocalGridPartType::template Codim<0>::EntityType& entity = *entityIt;
      // get basefunctionsets
      const auto testBase   = baseFunctionSet(entity);
      const auto ansatzBase = otherSpace.baseFunctionSet(entity);
      Dune::DynamicVector<size_t> globalRows(testBase.size(), 0);
      mapper().globalIndices(entity, globalRows);
      Dune::DynamicVector<size_t> globalCols(ansatzBase.size(), 0);
      otherSpace.mapper().globalIndices(entity, globalCols);
      for (size_t ii = 0; ii < testBase.size(); ++ii) {
        auto& columns = pattern.inner(globalRows[ii]);
        for (size_t jj = 0; jj < ansatzBase.size(); ++jj) {
          columns.insert(globalCols[jj]);
        }
      }
    } // walk the grid part
    return ret;
  } // ... computePattern(...)

  derived_type& asImp()
  {
    return static_cast<derived_type&>(*this);
  }

  const derived_type& asImp() const
  {
    return static_cast<const derived_type&>(*this);
  }
}; // class SpaceInterface

} // namespace Discretizations
} // namespace Detailed
} // namespace Dune

#endif // DUNE_DETAILED_DISCRETIZATIONS_SPACE_INTERFACE_HH
<commit_msg>[spaceinterface] added localConstraints()<commit_after>#ifndef DUNE_DETAILED_DISCRETIZATIONS_SPACE_INTERFACE_HH
#define DUNE_DETAILED_DISCRETIZATIONS_SPACE_INTERFACE_HH

#include <dune/common/bartonnackmanifcheck.hh>
#include <dune/common/dynvector.hh>

#include <dune/stuff/la/container/pattern.hh>

#include "constraints.hh"

namespace Dune {
namespace Detailed {
namespace Discretizations {

template <class Traits>
class SpaceInterface
{
public:
  typedef typename Traits::derived_type derived_type;

  typedef typename Traits::GridPartType GridPartType;
  static const int polOrder = Traits::polOrder;
  typedef typename GridPartType::ctype DomainFieldType;
  static const unsigned int dimDomain = GridPartType::dimension;
  typedef typename Traits::RangeFieldType RangeFieldType;
  static const unsigned int dimRangeRows = Traits::dimRangeRows;
  static const unsigned int dimRangeCols = Traits::dimRangeCols;

  typedef typename Traits::BackendType BackendType;
  typedef typename Traits::MapperType MapperType;
  typedef typename Traits::BaseFunctionSetType BaseFunctionSetType;
  typedef typename Traits::EntityType EntityType;

  typedef Dune::Stuff::LA::Container::SparsityPatternDefault PatternType;

  const GridPartType& gridPart() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().gridPart());
    return asImp().gridPart();
  }

  const BackendType& backend() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().backend());
    return asImp().backend();
  }

  bool continuous() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().continuous());
    return asImp().continuous();
  }

  const MapperType& mapper() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().mapper());
    return asImp().mapper();
  }

  BaseFunctionSetType baseFunctionSet(const EntityType& entity) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().baseFunctionSet(entity));
    return asImp().baseFunctionSet(entity);
  }

  template <class ConstraintsType>
  void localConstraints(const EntityType& entity, ConstraintsType& ret) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().localConstraints(entity, ret));
    asImp().localConstraints(entity, ret);
  }

  PatternType* computePattern() const
  {
    return computePattern(*this);
  }

  template <class OtherSpaceType>
  PatternType* computePattern(const OtherSpaceType& other) const
  {
    // check type of the other space
    return computePattern(gridPart(), other);
  }

  /**
   *  \brief  computes a sparsity pattern, where this space is the test space (rows/outer) and the other space is the
   *          ansatz space (cols/inner)
   */
  template <class LocalGridPartType, class O>
  PatternType* computePattern(const LocalGridPartType& localGridPart, const SpaceInterface<O>& otherSpace) const
  {
    typedef typename PatternType::size_type size_type;
    PatternType* ret     = new PatternType(mapper().size());
    PatternType& pattern = *ret;
    // walk the grid part
    for (typename LocalGridPartType::template Codim<0>::IteratorType entityIt = localGridPart.template begin<0>();
         entityIt != localGridPart.template end<0>();
         ++entityIt) {
      const typename LocalGridPartType::template Codim<0>::EntityType& entity = *entityIt;
      // get basefunctionsets
      const auto testBase   = baseFunctionSet(entity);
      const auto ansatzBase = otherSpace.baseFunctionSet(entity);
      Dune::DynamicVector<size_t> globalRows(testBase.size(), 0);
      mapper().globalIndices(entity, globalRows);
      Dune::DynamicVector<size_t> globalCols(ansatzBase.size(), 0);
      otherSpace.mapper().globalIndices(entity, globalCols);
      for (size_t ii = 0; ii < testBase.size(); ++ii) {
        auto& columns = pattern.inner(globalRows[ii]);
        for (size_t jj = 0; jj < ansatzBase.size(); ++jj) {
          columns.insert(globalCols[jj]);
        }
      }
    } // walk the grid part
    return ret;
  } // ... computePattern(...)

  derived_type& asImp()
  {
    return static_cast<derived_type&>(*this);
  }

  const derived_type& asImp() const
  {
    return static_cast<const derived_type&>(*this);
  }
}; // class SpaceInterface

} // namespace Discretizations
} // namespace Detailed
} // namespace Dune

#endif // DUNE_DETAILED_DISCRETIZATIONS_SPACE_INTERFACE_HH
<|endoftext|>