<commit_before>/*
 * projectM -- Milkdrop-esque visualisation SDK
 * Copyright (C)2003-2007 projectM Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * See 'LICENSE.txt' included within this release
 *
 */
/**
 * $Id: projectM.hpp,v 1.1.1.1 2005/12/23 18:05:11 psperl Exp $
 *
 * Encapsulation of ProjectM engine
 *
 * $Log$
 */

#ifndef _PROJECTM_HPP
#define _PROJECTM_HPP

#ifdef WIN32
#include "win32-dirent.h"
#else
#include <dirent.h>
#endif /** WIN32 */
#include <cmath>
#include <cstdio>
#include <string>
#include <cstdlib>
#ifndef WIN32
#include <unistd.h>
#endif
#include <sys/types.h>

#ifdef MACOS
//#include <MacWindows.h>
//#include <gl.h>
//#include <glu.h>
#else
#ifdef WIN32
#include <windows.h>
#endif /** WIN32 */

#endif /** MACOS */
#ifdef WIN322
#define inline
#endif /** WIN32 */

#include "dlldefs.h"
#include "event.h"
#include "fatal.h"
#include "PCM.hpp"
#include "pthread.h"
class PipelineContext;

#include <memory>

class BeatDetect;
class PCM;
class Func;
class Renderer;
class Preset;
class PresetIterator;
class PresetChooser;
class PresetLoader;
class TimeKeeper;
class Pipeline;
class RenderItemMatcher;
class MasterRenderItemMerge;

#include <memory>
#ifdef WIN32
#pragma warning (disable:4244)
#pragma warning (disable:4305)
#endif /** WIN32 */

#ifdef MACOS2
#define inline
#endif

/** KEEP THIS UP TO DATE! */
#define PROJECTM_VERSION "1.1.00"
#define PROJECTM_TITLE "projectM 1.1.00"

/** Interface types */
typedef enum {
    MENU_INTERFACE,
    SHELL_INTERFACE,
    EDITOR_INTERFACE,
    DEFAULT_INTERFACE,
    BROWSER_INTERFACE
  } interface_t;

/// A functor class that allows users of this library to specify random preset behavior
class RandomizerFunctor {

   public:
	RandomizerFunctor(PresetChooser & chooser) ;
	virtual ~RandomizerFunctor();
   	virtual double operator() (int index);
   private:
	const PresetChooser & m_chooser;
};

class DLLEXPORT projectM
{
public:
	static const int FLAG_NONE = 0;
	static const int FLAG_DISABLE_PLAYLIST_LOAD = 1 << 0;

    struct Settings {
        int meshX;
        int meshY;
        int fps;
        int textureSize;
        int windowWidth;
        int windowHeight;
        std::string presetURL;
        std::string titleFontURL;
        std::string menuFontURL;
        int smoothPresetDuration;
        int presetDuration;
        float beatSensitivity;
        bool aspectCorrection;
        float easterEgg;
        bool shuffleEnabled;
    };

  projectM(std::string config_file, int flags = FLAG_NONE);
  projectM(Settings settings, int flags = FLAG_NONE);

  //DLLEXPORT projectM(int gx, int gy, int fps, int texsize, int width, int height,std::string preset_url,std::string title_fonturl, std::string title_menuurl);

  void projectM_resetGL( int width, int height );
  void projectM_resetTextures();
  void projectM_setTitle( std::string title );
  void renderFrame();
  unsigned initRenderToTexture();
  void key_handler( projectMEvent event,
		    projectMKeycode keycode, projectMModifier modifier );

  virtual ~projectM();

  const Settings & settings() const {
		return _settings;
  }

  /// Writes a settings configuration to the specified file
  static bool writeConfig(const std::string & configFile, const Settings & settings);

  /// Sets preset iterator position to the passed in index
  void selectPresetPosition(unsigned int index);

  /// Plays a preset immediately
  void selectPreset(unsigned int index, bool hardCut = true);

  /// Removes a preset from the play list. If it is playing then it will continue as normal until next switch
  void removePreset(unsigned int index);

  /// Sets the randomization functor. If set to null, the traversal will move in order according to the playlist
  void setRandomizer(RandomizerFunctor * functor);

  /// Tell projectM to play a particular preset when it chooses to switch
  /// If the preset is locked the queued item will be not switched to until the lock is released
  /// Subsequent calls to this function effectively nullifies previous calls.
  void queuePreset(unsigned int index);

  /// Returns true if a preset is queued up to play next
  bool isPresetQueued() const;

  /// Removes entire playlist, The currently loaded preset will end up sticking until new presets are added
  void clearPlaylist();

  /// Turn on or off a lock that prevents projectM from switching to another preset
  void setPresetLock(bool isLocked);

  /// Returns true if the active preset is locked
  bool isPresetLocked() const;

  /// Returns index of currently active preset. In the case where the active
  /// preset was removed from the playlist, this function will return the element
  /// before active preset (thus the next in order preset is invariant with respect
  /// to the removal)
  bool selectedPresetIndex(unsigned int & index) const;

  /// Add a preset url to the play list. Appended to bottom. Returns index of preset
  unsigned int addPresetURL(const std::string & presetURL, const std::string & presetName, int rating);

  /// Insert a preset url to the play list at the suggested index.
  void insertPresetURL(unsigned int index,
			       const std::string & presetURL, const std::string & presetName, int rating);

  /// Returns true if the selected preset position points to an actual preset in the
  /// currently loaded playlist
  bool presetPositionValid() const;

  /// Returns the url associated with a preset index
  std::string getPresetURL(unsigned int index) const;

  /// Returns the preset name associated with a preset index
  std::string getPresetName ( unsigned int index ) const;

  /// Returns the rating associated with a preset index
  int getPresetRating (unsigned int index) const;

  void changePresetRating (unsigned int index, int rating);

  /// Returns the size of the play list
  unsigned int getPlaylistSize() const;

  void evaluateSecondPreset();

  inline void setShuffleEnabled(bool value)
  {
	  _settings.shuffleEnabled = value;

	/// idea@ call a virtualfunction shuffleChanged()
  }

  inline bool isShuffleEnabled() const
  {
	return _settings.shuffleEnabled;
  }

  /// Occurs when active preset has switched. Switched to index is returned
  virtual void presetSwitchedEvent(bool isHardCut, unsigned int index) const {};
  virtual void shuffleEnabledValueChanged(bool isEnabled) const {};

  inline PCM * pcm() {
	  return _pcm;
  }
  void *thread_func(void *vptr_args);
  PipelineContext & pipelineContext() { return *_pipelineContext; }
  PipelineContext & pipelineContext2() { return *_pipelineContext2; }

private:
  PCM * _pcm;
  double sampledPresetDuration();
  BeatDetect * beatDetect;
  Renderer *renderer;
  PipelineContext * _pipelineContext;
  PipelineContext * _pipelineContext2;
  Settings _settings;

  int wvw;      //windowed dimensions
  int wvh;

  /** Timing information */
  int mspf;
  int timed;
  int timestart;
  int count;
  float fpsstart;

  void readConfig(const std::string &configFile);
  void readSettings(const Settings &settings);
  void projectM_init(int gx, int gy, int fps, int texsize, int width, int height);
  void projectM_reset();
  void selectPrevious(const bool);
  void selectNext(const bool);
  void selectRandom(const bool);

  void projectM_initengine();
  void projectM_resetengine();

  /// Initializes preset loading / management libraries
  int initPresetTools(int gx, int gy);

  /// Deinitialize all preset related tools. Usually done before projectM cleanup
  void destroyPresetTools();

  void default_key_handler( projectMEvent event, projectMKeycode keycode );
  /// The current position of the directory iterator
  PresetIterator * m_presetPos;

  /// Required by the preset chooser. Manages a loaded preset directory
  PresetLoader * m_presetLoader;

  /// Provides accessor functions to choose presets
  PresetChooser * m_presetChooser;

  /// Currently loaded preset
  std::auto_ptr<Preset> m_activePreset;

  /// Destination preset when smooth preset switching
  std::auto_ptr<Preset> m_activePreset2;

  TimeKeeper *timeKeeper;

  int m_flags;

  RenderItemMatcher * _matcher;
  MasterRenderItemMerge * _merger;
  pthread_mutex_t mutex;
  pthread_cond_t  condition;
  pthread_t thread;
  bool running;

  Pipeline* currentPipe;

void switchPreset(std::auto_ptr<Preset> & targetPreset);

};
#endif
<commit_msg>version bump.<commit_after>/*
 * projectM -- Milkdrop-esque visualisation SDK
 * Copyright (C)2003-2007 projectM Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * See 'LICENSE.txt' included within this release
 *
 */
/**
 * $Id: projectM.hpp,v 1.1.1.1 2005/12/23 18:05:11 psperl Exp $
 *
 * Encapsulation of ProjectM engine
 *
 * $Log$
 */

#ifndef _PROJECTM_HPP
#define _PROJECTM_HPP

#ifdef WIN32
#include "win32-dirent.h"
#else
#include <dirent.h>
#endif /** WIN32 */
#include <cmath>
#include <cstdio>
#include <string>
#include <cstdlib>
#ifndef WIN32
#include <unistd.h>
#endif
#include <sys/types.h>

#ifdef MACOS
//#include <MacWindows.h>
//#include <gl.h>
//#include <glu.h>
#else
#ifdef WIN32
#include <windows.h>
#endif /** WIN32 */

#endif /** MACOS */
#ifdef WIN322
#define inline
#endif /** WIN32 */

#include "dlldefs.h"
#include "event.h"
#include "fatal.h"
#include "PCM.hpp"
#include "pthread.h"
class PipelineContext;

#include <memory>

class BeatDetect;
class PCM;
class Func;
class Renderer;
class Preset;
class PresetIterator;
class PresetChooser;
class PresetLoader;
class TimeKeeper;
class Pipeline;
class RenderItemMatcher;
class MasterRenderItemMerge;

#include <memory>
#ifdef WIN32
#pragma warning (disable:4244)
#pragma warning (disable:4305)
#endif /** WIN32 */

#ifdef MACOS2
#define inline
#endif

/** KEEP THIS UP TO DATE! */
#define PROJECTM_VERSION "2.0.00"
#define PROJECTM_TITLE "projectM 2.0.00"

/** Interface types */
typedef enum {
    MENU_INTERFACE,
    SHELL_INTERFACE,
    EDITOR_INTERFACE,
    DEFAULT_INTERFACE,
    BROWSER_INTERFACE
  } interface_t;

/// A functor class that allows users of this library to specify random preset behavior
class RandomizerFunctor {

   public:
	RandomizerFunctor(PresetChooser & chooser) ;
	virtual ~RandomizerFunctor();
   	virtual double operator() (int index);
   private:
	const PresetChooser & m_chooser;
};

class DLLEXPORT projectM
{
public:
	static const int FLAG_NONE = 0;
	static const int FLAG_DISABLE_PLAYLIST_LOAD = 1 << 0;

    struct Settings {
        int meshX;
        int meshY;
        int fps;
        int textureSize;
        int windowWidth;
        int windowHeight;
        std::string presetURL;
        std::string titleFontURL;
        std::string menuFontURL;
        int smoothPresetDuration;
        int presetDuration;
        float beatSensitivity;
        bool aspectCorrection;
        float easterEgg;
        bool shuffleEnabled;
    };

  projectM(std::string config_file, int flags = FLAG_NONE);
  projectM(Settings settings, int flags = FLAG_NONE);

  //DLLEXPORT projectM(int gx, int gy, int fps, int texsize, int width, int height,std::string preset_url,std::string title_fonturl, std::string title_menuurl);

  void projectM_resetGL( int width, int height );
  void projectM_resetTextures();
  void projectM_setTitle( std::string title );
  void renderFrame();
  unsigned initRenderToTexture();
  void key_handler( projectMEvent event,
		    projectMKeycode keycode, projectMModifier modifier );

  virtual ~projectM();

  const Settings & settings() const {
		return _settings;
  }

  /// Writes a settings configuration to the specified file
  static bool writeConfig(const std::string & configFile, const Settings & settings);

  /// Sets preset iterator position to the passed in index
  void selectPresetPosition(unsigned int index);

  /// Plays a preset immediately
  void selectPreset(unsigned int index, bool hardCut = true);

  /// Removes a preset from the play list. If it is playing then it will continue as normal until next switch
  void removePreset(unsigned int index);

  /// Sets the randomization functor. If set to null, the traversal will move in order according to the playlist
  void setRandomizer(RandomizerFunctor * functor);

  /// Tell projectM to play a particular preset when it chooses to switch
  /// If the preset is locked the queued item will be not switched to until the lock is released
  /// Subsequent calls to this function effectively nullifies previous calls.
  void queuePreset(unsigned int index);

  /// Returns true if a preset is queued up to play next
  bool isPresetQueued() const;

  /// Removes entire playlist, The currently loaded preset will end up sticking until new presets are added
  void clearPlaylist();

  /// Turn on or off a lock that prevents projectM from switching to another preset
  void setPresetLock(bool isLocked);

  /// Returns true if the active preset is locked
  bool isPresetLocked() const;

  /// Returns index of currently active preset. In the case where the active
  /// preset was removed from the playlist, this function will return the element
  /// before active preset (thus the next in order preset is invariant with respect
  /// to the removal)
  bool selectedPresetIndex(unsigned int & index) const;

  /// Add a preset url to the play list. Appended to bottom. Returns index of preset
  unsigned int addPresetURL(const std::string & presetURL, const std::string & presetName, int rating);

  /// Insert a preset url to the play list at the suggested index.
  void insertPresetURL(unsigned int index,
			       const std::string & presetURL, const std::string & presetName, int rating);

  /// Returns true if the selected preset position points to an actual preset in the
  /// currently loaded playlist
  bool presetPositionValid() const;

  /// Returns the url associated with a preset index
  std::string getPresetURL(unsigned int index) const;

  /// Returns the preset name associated with a preset index
  std::string getPresetName ( unsigned int index ) const;

  /// Returns the rating associated with a preset index
  int getPresetRating (unsigned int index) const;

  void changePresetRating (unsigned int index, int rating);

  /// Returns the size of the play list
  unsigned int getPlaylistSize() const;

  void evaluateSecondPreset();

  inline void setShuffleEnabled(bool value)
  {
	  _settings.shuffleEnabled = value;

	/// idea@ call a virtualfunction shuffleChanged()
  }

  inline bool isShuffleEnabled() const
  {
	return _settings.shuffleEnabled;
  }

  /// Occurs when active preset has switched. Switched to index is returned
  virtual void presetSwitchedEvent(bool isHardCut, unsigned int index) const {};
  virtual void shuffleEnabledValueChanged(bool isEnabled) const {};

  inline PCM * pcm() {
	  return _pcm;
  }
  void *thread_func(void *vptr_args);
  PipelineContext & pipelineContext() { return *_pipelineContext; }
  PipelineContext & pipelineContext2() { return *_pipelineContext2; }

private:
  PCM * _pcm;
  double sampledPresetDuration();
  BeatDetect * beatDetect;
  Renderer *renderer;
  PipelineContext * _pipelineContext;
  PipelineContext * _pipelineContext2;
  Settings _settings;

  int wvw;      //windowed dimensions
  int wvh;

  /** Timing information */
  int mspf;
  int timed;
  int timestart;
  int count;
  float fpsstart;

  void readConfig(const std::string &configFile);
  void readSettings(const Settings &settings);
  void projectM_init(int gx, int gy, int fps, int texsize, int width, int height);
  void projectM_reset();
  void selectPrevious(const bool);
  void selectNext(const bool);
  void selectRandom(const bool);

  void projectM_initengine();
  void projectM_resetengine();

  /// Initializes preset loading / management libraries
  int initPresetTools(int gx, int gy);

  /// Deinitialize all preset related tools. Usually done before projectM cleanup
  void destroyPresetTools();

  void default_key_handler( projectMEvent event, projectMKeycode keycode );
  /// The current position of the directory iterator
  PresetIterator * m_presetPos;

  /// Required by the preset chooser. Manages a loaded preset directory
  PresetLoader * m_presetLoader;

  /// Provides accessor functions to choose presets
  PresetChooser * m_presetChooser;

  /// Currently loaded preset
  std::auto_ptr<Preset> m_activePreset;

  /// Destination preset when smooth preset switching
  std::auto_ptr<Preset> m_activePreset2;

  TimeKeeper *timeKeeper;

  int m_flags;

  RenderItemMatcher * _matcher;
  MasterRenderItemMerge * _merger;
  pthread_mutex_t mutex;
  pthread_cond_t  condition;
  pthread_t thread;
  bool running;

  Pipeline* currentPipe;

void switchPreset(std::auto_ptr<Preset> & targetPreset);

};
#endif
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. 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 "benchmark_register.h"

#ifndef BENCHMARK_OS_WINDOWS
#ifndef BENCHMARK_OS_FUCHSIA
#include <sys/resource.h>
#endif
#include <sys/time.h>
#include <unistd.h>
#endif

#include <algorithm>
#include <atomic>
#include <cinttypes>
#include <condition_variable>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <numeric>
#include <sstream>
#include <thread>

#include "benchmark/benchmark.h"
#include "benchmark_api_internal.h"
#include "check.h"
#include "commandlineflags.h"
#include "complexity.h"
#include "internal_macros.h"
#include "log.h"
#include "mutex.h"
#include "re.h"
#include "statistics.h"
#include "string_util.h"
#include "timers.h"

namespace benchmark {

namespace {
// For non-dense Range, intermediate values are powers of kRangeMultiplier.
static const int kRangeMultiplier = 8;
// The size of a benchmark family determines is the number of inputs to repeat
// the benchmark on. If this is "large" then warn the user during configuration.
static const size_t kMaxFamilySize = 100;
}  // end namespace

namespace internal {

//=============================================================================//
//                         BenchmarkFamilies
//=============================================================================//

// Class for managing registered benchmarks.  Note that each registered
// benchmark identifies a family of related benchmarks to run.
class BenchmarkFamilies {
 public:
  static BenchmarkFamilies* GetInstance();

  // Registers a benchmark family and returns the index assigned to it.
  size_t AddBenchmark(std::unique_ptr<Benchmark> family);

  // Clear all registered benchmark families.
  void ClearBenchmarks();

  // Extract the list of benchmark instances that match the specified
  // regular expression.
  bool FindBenchmarks(std::string re,
                      std::vector<BenchmarkInstance>* benchmarks,
                      std::ostream* Err);

 private:
  BenchmarkFamilies() {}

  std::vector<std::unique_ptr<Benchmark>> families_;
  Mutex mutex_;
};

BenchmarkFamilies* BenchmarkFamilies::GetInstance() {
  static BenchmarkFamilies instance;
  return &instance;
}

size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr<Benchmark> family) {
  MutexLock l(mutex_);
  size_t index = families_.size();
  families_.push_back(std::move(family));
  return index;
}

void BenchmarkFamilies::ClearBenchmarks() {
  MutexLock l(mutex_);
  families_.clear();
  families_.shrink_to_fit();
}

bool BenchmarkFamilies::FindBenchmarks(
    std::string spec, std::vector<BenchmarkInstance>* benchmarks,
    std::ostream* ErrStream) {
  CHECK(ErrStream);
  auto& Err = *ErrStream;
  // Make regular expression out of command-line flag
  std::string error_msg;
  Regex re;
  bool isNegativeFilter = false;
  if (spec[0] == '-') {
    spec.replace(0, 1, "");
    isNegativeFilter = true;
  }
  if (!re.Init(spec, &error_msg)) {
    Err << "Could not compile benchmark re: " << error_msg << std::endl;
    return false;
  }

  // Special list of thread counts to use when none are specified
  const std::vector<int> one_thread = {1};

  MutexLock l(mutex_);
  for (std::unique_ptr<Benchmark>& family : families_) {
    // Family was deleted or benchmark doesn't match
    if (!family) continue;

    if (family->ArgsCnt() == -1) {
      family->Args({});
    }
    const std::vector<int>* thread_counts =
        (family->thread_counts_.empty()
             ? &one_thread
             : &static_cast<const std::vector<int>&>(family->thread_counts_));
    const size_t family_size = family->args_.size() * thread_counts->size();
    // The benchmark will be run at least 'family_size' different inputs.
    // If 'family_size' is very large warn the user.
    if (family_size > kMaxFamilySize) {
      Err << "The number of inputs is very large. " << family->name_
          << " will be repeated at least " << family_size << " times.\n";
    }
    // reserve in the special case the regex ".", since we know the final
    // family size.
    if (spec == ".") benchmarks->reserve(family_size);

    for (auto const& args : family->args_) {
      for (int num_threads : *thread_counts) {
        BenchmarkInstance instance(family.get(), args, num_threads);

        const auto full_name = instance.name().str();
        if ((re.Match(full_name) && !isNegativeFilter) ||
            (!re.Match(full_name) && isNegativeFilter)) {
          instance.last_benchmark_instance = (&args == &family->args_.back());
          benchmarks->push_back(std::move(instance));
        }
      }
    }
  }
  return true;
}

Benchmark* RegisterBenchmarkInternal(Benchmark* bench) {
  std::unique_ptr<Benchmark> bench_ptr(bench);
  BenchmarkFamilies* families = BenchmarkFamilies::GetInstance();
  families->AddBenchmark(std::move(bench_ptr));
  return bench;
}

// FIXME: This function is a hack so that benchmark.cc can access
// `BenchmarkFamilies`
bool FindBenchmarksInternal(const std::string& re,
                            std::vector<BenchmarkInstance>* benchmarks,
                            std::ostream* Err) {
  return BenchmarkFamilies::GetInstance()->FindBenchmarks(re, benchmarks, Err);
}

//=============================================================================//
//                               Benchmark
//=============================================================================//

Benchmark::Benchmark(const char* name)
    : name_(name),
      aggregation_report_mode_(ARM_Unspecified),
      time_unit_(kNanosecond),
      range_multiplier_(kRangeMultiplier),
      min_time_(0),
      iterations_(0),
      repetitions_(0),
      measure_process_cpu_time_(false),
      use_real_time_(false),
      use_manual_time_(false),
      complexity_(oNone),
      complexity_lambda_(nullptr) {
  ComputeStatistics("mean", StatisticsMean);
  ComputeStatistics("median", StatisticsMedian);
  ComputeStatistics("stddev", StatisticsStdDev);
}

Benchmark::~Benchmark() {}

Benchmark* Benchmark::Name(const std::string& name) {
  SetName(name.c_str());
  return this;
}

Benchmark* Benchmark::Arg(int64_t x) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
  args_.push_back({x});
  return this;
}

Benchmark* Benchmark::Unit(TimeUnit unit) {
  time_unit_ = unit;
  return this;
}

Benchmark* Benchmark::Range(int64_t start, int64_t limit) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
  std::vector<int64_t> arglist;
  AddRange(&arglist, start, limit, range_multiplier_);

  for (int64_t i : arglist) {
    args_.push_back({i});
  }
  return this;
}

Benchmark* Benchmark::Ranges(
    const std::vector<std::pair<int64_t, int64_t>>& ranges) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(ranges.size()));
  std::vector<std::vector<int64_t>> arglists(ranges.size());
  for (std::size_t i = 0; i < ranges.size(); i++) {
    AddRange(&arglists[i], ranges[i].first, ranges[i].second,
             range_multiplier_);
  }

  ArgsProduct(arglists);

  return this;
}

Benchmark* Benchmark::ArgsProduct(
    const std::vector<std::vector<int64_t>>& arglists) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(arglists.size()));

  std::vector<std::size_t> indices(arglists.size());
  const std::size_t total = std::accumulate(
      std::begin(arglists), std::end(arglists), std::size_t{1},
      [](const std::size_t res, const std::vector<int64_t>& arglist) {
        return res * arglist.size();
      });
  std::vector<int64_t> args;
  args.reserve(arglists.size());
  for (std::size_t i = 0; i < total; i++) {
    for (std::size_t arg = 0; arg < arglists.size(); arg++) {
      args.push_back(arglists[arg][indices[arg]]);
    }
    args_.push_back(args);
    args.clear();

    std::size_t arg = 0;
    do {
      indices[arg] = (indices[arg] + 1) % arglists[arg].size();
    } while (indices[arg++] == 0 && arg < arglists.size());
  }

  return this;
}

Benchmark* Benchmark::ArgName(const std::string& name) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
  arg_names_ = {name};
  return this;
}

Benchmark* Benchmark::ArgNames(const std::vector<std::string>& names) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(names.size()));
  arg_names_ = names;
  return this;
}

Benchmark* Benchmark::DenseRange(int64_t start, int64_t limit, int step) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
  CHECK_LE(start, limit);
  for (int64_t arg = start; arg <= limit; arg += step) {
    args_.push_back({arg});
  }
  return this;
}

Benchmark* Benchmark::Args(const std::vector<int64_t>& args) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(args.size()));
  args_.push_back(args);
  return this;
}

Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) {
  custom_arguments(this);
  return this;
}

Benchmark* Benchmark::RangeMultiplier(int multiplier) {
  CHECK(multiplier > 1);
  range_multiplier_ = multiplier;
  return this;
}

Benchmark* Benchmark::MinTime(double t) {
  CHECK(t > 0.0);
  CHECK(iterations_ == 0);
  min_time_ = t;
  return this;
}

Benchmark* Benchmark::Iterations(IterationCount n) {
  CHECK(n > 0);
  CHECK(IsZero(min_time_));
  iterations_ = n;
  return this;
}

Benchmark* Benchmark::Repetitions(int n) {
  CHECK(n > 0);
  repetitions_ = n;
  return this;
}

Benchmark* Benchmark::ReportAggregatesOnly(bool value) {
  aggregation_report_mode_ = value ? ARM_ReportAggregatesOnly : ARM_Default;
  return this;
}

Benchmark* Benchmark::DisplayAggregatesOnly(bool value) {
  // If we were called, the report mode is no longer 'unspecified', in any case.
  aggregation_report_mode_ = static_cast<AggregationReportMode>(
      aggregation_report_mode_ | ARM_Default);

  if (value) {
    aggregation_report_mode_ = static_cast<AggregationReportMode>(
        aggregation_report_mode_ | ARM_DisplayReportAggregatesOnly);
  } else {
    aggregation_report_mode_ = static_cast<AggregationReportMode>(
        aggregation_report_mode_ & ~ARM_DisplayReportAggregatesOnly);
  }

  return this;
}

Benchmark* Benchmark::MeasureProcessCPUTime() {
  // Can be used together with UseRealTime() / UseManualTime().
  measure_process_cpu_time_ = true;
  return this;
}

Benchmark* Benchmark::UseRealTime() {
  CHECK(!use_manual_time_)
      << "Cannot set UseRealTime and UseManualTime simultaneously.";
  use_real_time_ = true;
  return this;
}

Benchmark* Benchmark::UseManualTime() {
  CHECK(!use_real_time_)
      << "Cannot set UseRealTime and UseManualTime simultaneously.";
  use_manual_time_ = true;
  return this;
}

Benchmark* Benchmark::Complexity(BigO complexity) {
  complexity_ = complexity;
  return this;
}

Benchmark* Benchmark::Complexity(BigOFunc* complexity) {
  complexity_lambda_ = complexity;
  complexity_ = oLambda;
  return this;
}

Benchmark* Benchmark::ComputeStatistics(std::string name,
                                        StatisticsFunc* statistics) {
  statistics_.emplace_back(name, statistics);
  return this;
}

Benchmark* Benchmark::Threads(int t) {
  CHECK_GT(t, 0);
  thread_counts_.push_back(t);
  return this;
}

Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) {
  CHECK_GT(min_threads, 0);
  CHECK_GE(max_threads, min_threads);

  AddRange(&thread_counts_, min_threads, max_threads, 2);
  return this;
}

Benchmark* Benchmark::DenseThreadRange(int min_threads, int max_threads,
                                       int stride) {
  CHECK_GT(min_threads, 0);
  CHECK_GE(max_threads, min_threads);
  CHECK_GE(stride, 1);

  for (auto i = min_threads; i < max_threads; i += stride) {
    thread_counts_.push_back(i);
  }
  thread_counts_.push_back(max_threads);
  return this;
}

Benchmark* Benchmark::ThreadPerCpu() {
  thread_counts_.push_back(CPUInfo::Get().num_cpus);
  return this;
}

void Benchmark::SetName(const char* name) { name_ = name; }

int Benchmark::ArgsCnt() const {
  if (args_.empty()) {
    if (arg_names_.empty()) return -1;
    return static_cast<int>(arg_names_.size());
  }
  return static_cast<int>(args_.front().size());
}

//=============================================================================//
//                            FunctionBenchmark
//=============================================================================//

void FunctionBenchmark::Run(State& st) { func_(st); }

}  // end namespace internal

void ClearRegisteredBenchmarks() {
  internal::BenchmarkFamilies::GetInstance()->ClearBenchmarks();
}

}  // end namespace benchmark
<commit_msg>Change a check in DenseRange: on the one hand, going from -5 to 3 with step of 1 makes perfect sense, on the other hand a negative step would cause trouble.<commit_after>// Copyright 2015 Google Inc. 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 "benchmark_register.h"

#ifndef BENCHMARK_OS_WINDOWS
#ifndef BENCHMARK_OS_FUCHSIA
#include <sys/resource.h>
#endif
#include <sys/time.h>
#include <unistd.h>
#endif

#include <algorithm>
#include <atomic>
#include <cinttypes>
#include <condition_variable>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <numeric>
#include <sstream>
#include <thread>

#include "benchmark/benchmark.h"
#include "benchmark_api_internal.h"
#include "check.h"
#include "commandlineflags.h"
#include "complexity.h"
#include "internal_macros.h"
#include "log.h"
#include "mutex.h"
#include "re.h"
#include "statistics.h"
#include "string_util.h"
#include "timers.h"

namespace benchmark {

namespace {
// For non-dense Range, intermediate values are powers of kRangeMultiplier.
static const int kRangeMultiplier = 8;
// The size of a benchmark family determines is the number of inputs to repeat
// the benchmark on. If this is "large" then warn the user during configuration.
static const size_t kMaxFamilySize = 100;
}  // end namespace

namespace internal {

//=============================================================================//
//                         BenchmarkFamilies
//=============================================================================//

// Class for managing registered benchmarks.  Note that each registered
// benchmark identifies a family of related benchmarks to run.
class BenchmarkFamilies {
 public:
  static BenchmarkFamilies* GetInstance();

  // Registers a benchmark family and returns the index assigned to it.
  size_t AddBenchmark(std::unique_ptr<Benchmark> family);

  // Clear all registered benchmark families.
  void ClearBenchmarks();

  // Extract the list of benchmark instances that match the specified
  // regular expression.
  bool FindBenchmarks(std::string re,
                      std::vector<BenchmarkInstance>* benchmarks,
                      std::ostream* Err);

 private:
  BenchmarkFamilies() {}

  std::vector<std::unique_ptr<Benchmark>> families_;
  Mutex mutex_;
};

BenchmarkFamilies* BenchmarkFamilies::GetInstance() {
  static BenchmarkFamilies instance;
  return &instance;
}

size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr<Benchmark> family) {
  MutexLock l(mutex_);
  size_t index = families_.size();
  families_.push_back(std::move(family));
  return index;
}

void BenchmarkFamilies::ClearBenchmarks() {
  MutexLock l(mutex_);
  families_.clear();
  families_.shrink_to_fit();
}

bool BenchmarkFamilies::FindBenchmarks(
    std::string spec, std::vector<BenchmarkInstance>* benchmarks,
    std::ostream* ErrStream) {
  CHECK(ErrStream);
  auto& Err = *ErrStream;
  // Make regular expression out of command-line flag
  std::string error_msg;
  Regex re;
  bool isNegativeFilter = false;
  if (spec[0] == '-') {
    spec.replace(0, 1, "");
    isNegativeFilter = true;
  }
  if (!re.Init(spec, &error_msg)) {
    Err << "Could not compile benchmark re: " << error_msg << std::endl;
    return false;
  }

  // Special list of thread counts to use when none are specified
  const std::vector<int> one_thread = {1};

  MutexLock l(mutex_);
  for (std::unique_ptr<Benchmark>& family : families_) {
    // Family was deleted or benchmark doesn't match
    if (!family) continue;

    if (family->ArgsCnt() == -1) {
      family->Args({});
    }
    const std::vector<int>* thread_counts =
        (family->thread_counts_.empty()
             ? &one_thread
             : &static_cast<const std::vector<int>&>(family->thread_counts_));
    const size_t family_size = family->args_.size() * thread_counts->size();
    // The benchmark will be run at least 'family_size' different inputs.
    // If 'family_size' is very large warn the user.
    if (family_size > kMaxFamilySize) {
      Err << "The number of inputs is very large. " << family->name_
          << " will be repeated at least " << family_size << " times.\n";
    }
    // reserve in the special case the regex ".", since we know the final
    // family size.
    if (spec == ".") benchmarks->reserve(family_size);

    for (auto const& args : family->args_) {
      for (int num_threads : *thread_counts) {
        BenchmarkInstance instance(family.get(), args, num_threads);

        const auto full_name = instance.name().str();
        if ((re.Match(full_name) && !isNegativeFilter) ||
            (!re.Match(full_name) && isNegativeFilter)) {
          instance.last_benchmark_instance = (&args == &family->args_.back());
          benchmarks->push_back(std::move(instance));
        }
      }
    }
  }
  return true;
}

Benchmark* RegisterBenchmarkInternal(Benchmark* bench) {
  std::unique_ptr<Benchmark> bench_ptr(bench);
  BenchmarkFamilies* families = BenchmarkFamilies::GetInstance();
  families->AddBenchmark(std::move(bench_ptr));
  return bench;
}

// FIXME: This function is a hack so that benchmark.cc can access
// `BenchmarkFamilies`
bool FindBenchmarksInternal(const std::string& re,
                            std::vector<BenchmarkInstance>* benchmarks,
                            std::ostream* Err) {
  return BenchmarkFamilies::GetInstance()->FindBenchmarks(re, benchmarks, Err);
}

//=============================================================================//
//                               Benchmark
//=============================================================================//

Benchmark::Benchmark(const char* name)
    : name_(name),
      aggregation_report_mode_(ARM_Unspecified),
      time_unit_(kNanosecond),
      range_multiplier_(kRangeMultiplier),
      min_time_(0),
      iterations_(0),
      repetitions_(0),
      measure_process_cpu_time_(false),
      use_real_time_(false),
      use_manual_time_(false),
      complexity_(oNone),
      complexity_lambda_(nullptr) {
  ComputeStatistics("mean", StatisticsMean);
  ComputeStatistics("median", StatisticsMedian);
  ComputeStatistics("stddev", StatisticsStdDev);
}

Benchmark::~Benchmark() {}

Benchmark* Benchmark::Name(const std::string& name) {
  SetName(name.c_str());
  return this;
}

Benchmark* Benchmark::Arg(int64_t x) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
  args_.push_back({x});
  return this;
}

Benchmark* Benchmark::Unit(TimeUnit unit) {
  time_unit_ = unit;
  return this;
}

Benchmark* Benchmark::Range(int64_t start, int64_t limit) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
  std::vector<int64_t> arglist;
  AddRange(&arglist, start, limit, range_multiplier_);

  for (int64_t i : arglist) {
    args_.push_back({i});
  }
  return this;
}

Benchmark* Benchmark::Ranges(
    const std::vector<std::pair<int64_t, int64_t>>& ranges) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(ranges.size()));
  std::vector<std::vector<int64_t>> arglists(ranges.size());
  for (std::size_t i = 0; i < ranges.size(); i++) {
    AddRange(&arglists[i], ranges[i].first, ranges[i].second,
             range_multiplier_);
  }

  ArgsProduct(arglists);

  return this;
}

Benchmark* Benchmark::ArgsProduct(
    const std::vector<std::vector<int64_t>>& arglists) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(arglists.size()));

  std::vector<std::size_t> indices(arglists.size());
  const std::size_t total = std::accumulate(
      std::begin(arglists), std::end(arglists), std::size_t{1},
      [](const std::size_t res, const std::vector<int64_t>& arglist) {
        return res * arglist.size();
      });
  std::vector<int64_t> args;
  args.reserve(arglists.size());
  for (std::size_t i = 0; i < total; i++) {
    for (std::size_t arg = 0; arg < arglists.size(); arg++) {
      args.push_back(arglists[arg][indices[arg]]);
    }
    args_.push_back(args);
    args.clear();

    std::size_t arg = 0;
    do {
      indices[arg] = (indices[arg] + 1) % arglists[arg].size();
    } while (indices[arg++] == 0 && arg < arglists.size());
  }

  return this;
}

Benchmark* Benchmark::ArgName(const std::string& name) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
  arg_names_ = {name};
  return this;
}

Benchmark* Benchmark::ArgNames(const std::vector<std::string>& names) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(names.size()));
  arg_names_ = names;
  return this;
}

Benchmark* Benchmark::DenseRange(int64_t start, int64_t limit, int step) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
  CHECK_GT(step, 0);
  CHECK_LE(start, limit);
  for (int64_t arg = start; arg <= limit; arg += step) {
    args_.push_back({arg});
  }
  return this;
}

Benchmark* Benchmark::Args(const std::vector<int64_t>& args) {
  CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(args.size()));
  args_.push_back(args);
  return this;
}

Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) {
  custom_arguments(this);
  return this;
}

Benchmark* Benchmark::RangeMultiplier(int multiplier) {
  CHECK(multiplier > 1);
  range_multiplier_ = multiplier;
  return this;
}

Benchmark* Benchmark::MinTime(double t) {
  CHECK(t > 0.0);
  CHECK(iterations_ == 0);
  min_time_ = t;
  return this;
}

Benchmark* Benchmark::Iterations(IterationCount n) {
  CHECK(n > 0);
  CHECK(IsZero(min_time_));
  iterations_ = n;
  return this;
}

Benchmark* Benchmark::Repetitions(int n) {
  CHECK(n > 0);
  repetitions_ = n;
  return this;
}

Benchmark* Benchmark::ReportAggregatesOnly(bool value) {
  aggregation_report_mode_ = value ? ARM_ReportAggregatesOnly : ARM_Default;
  return this;
}

Benchmark* Benchmark::DisplayAggregatesOnly(bool value) {
  // If we were called, the report mode is no longer 'unspecified', in any case.
  aggregation_report_mode_ = static_cast<AggregationReportMode>(
      aggregation_report_mode_ | ARM_Default);

  if (value) {
    aggregation_report_mode_ = static_cast<AggregationReportMode>(
        aggregation_report_mode_ | ARM_DisplayReportAggregatesOnly);
  } else {
    aggregation_report_mode_ = static_cast<AggregationReportMode>(
        aggregation_report_mode_ & ~ARM_DisplayReportAggregatesOnly);
  }

  return this;
}

Benchmark* Benchmark::MeasureProcessCPUTime() {
  // Can be used together with UseRealTime() / UseManualTime().
  measure_process_cpu_time_ = true;
  return this;
}

Benchmark* Benchmark::UseRealTime() {
  CHECK(!use_manual_time_)
      << "Cannot set UseRealTime and UseManualTime simultaneously.";
  use_real_time_ = true;
  return this;
}

Benchmark* Benchmark::UseManualTime() {
  CHECK(!use_real_time_)
      << "Cannot set UseRealTime and UseManualTime simultaneously.";
  use_manual_time_ = true;
  return this;
}

Benchmark* Benchmark::Complexity(BigO complexity) {
  complexity_ = complexity;
  return this;
}

Benchmark* Benchmark::Complexity(BigOFunc* complexity) {
  complexity_lambda_ = complexity;
  complexity_ = oLambda;
  return this;
}

Benchmark* Benchmark::ComputeStatistics(std::string name,
                                        StatisticsFunc* statistics) {
  statistics_.emplace_back(name, statistics);
  return this;
}

Benchmark* Benchmark::Threads(int t) {
  CHECK_GT(t, 0);
  thread_counts_.push_back(t);
  return this;
}

Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) {
  CHECK_GT(min_threads, 0);
  CHECK_GE(max_threads, min_threads);

  AddRange(&thread_counts_, min_threads, max_threads, 2);
  return this;
}

Benchmark* Benchmark::DenseThreadRange(int min_threads, int max_threads,
                                       int stride) {
  CHECK_GT(min_threads, 0);
  CHECK_GE(max_threads, min_threads);
  CHECK_GE(stride, 1);

  for (auto i = min_threads; i < max_threads; i += stride) {
    thread_counts_.push_back(i);
  }
  thread_counts_.push_back(max_threads);
  return this;
}

Benchmark* Benchmark::ThreadPerCpu() {
  thread_counts_.push_back(CPUInfo::Get().num_cpus);
  return this;
}

void Benchmark::SetName(const char* name) { name_ = name; }

int Benchmark::ArgsCnt() const {
  if (args_.empty()) {
    if (arg_names_.empty()) return -1;
    return static_cast<int>(arg_names_.size());
  }
  return static_cast<int>(args_.front().size());
}

//=============================================================================//
//                            FunctionBenchmark
//=============================================================================//

void FunctionBenchmark::Run(State& st) { func_(st); }

}  // end namespace internal

void ClearRegisteredBenchmarks() {
  internal::BenchmarkFamilies::GetInstance()->ClearBenchmarks();
}

}  // end namespace benchmark
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "elfreader.h"
#include "qtcassert.h"

#include <QFile>
#include <QLibrary>
#include <QDebug>

namespace Utils {

quint16 getHalfWord(const unsigned char *&s, const ElfData &context)
{
    quint16 res;
    if (context.endian == Elf_ELFDATA2MSB)
        res = qFromBigEndian<quint16>(s);
    else
        res = qFromLittleEndian<quint16>(s);
    s += 2;
    return res;
}

quint32 getWord(const unsigned char *&s, const ElfData &context)
{
    quint32 res;
    if (context.endian == Elf_ELFDATA2MSB)
        res = qFromBigEndian<quint32>(s);
    else
        res = qFromLittleEndian<quint32>(s);
    s += 4;
    return res;
}

quint64 getAddress(const unsigned char *&s, const ElfData &context)
{
    quint64 res;
    if (context.elfclass == Elf_ELFCLASS32) {
        if (context.endian == Elf_ELFDATA2MSB)
            res = qFromBigEndian<quint32>(s);
        else
            res = qFromLittleEndian<quint32>(s);
        s += 4;
    } else {
        if (context.endian == Elf_ELFDATA2MSB)
            res = qFromBigEndian<quint64>(s);
        else
            res = qFromLittleEndian<quint64>(s);
        s += 8;
    }
    return res;
}

quint64 getOffset(const unsigned char *&s, const ElfData &context)
{
    return getAddress(s, context);
}

static void parseSectionHeader(const uchar *s, ElfSectionHeader *sh, const ElfData &context)
{
    sh->index = getWord(s, context);
    sh->type = getWord(s, context);
    sh->flags = getOffset(s, context);
    sh->addr = getAddress(s, context);
    sh->offset = getOffset(s, context);
    sh->size = getOffset(s, context);
}

static void parseProgramHeader(const uchar *s, ElfProgramHeader *sh, const ElfData &context)
{
    sh->type = getWord(s, context);
    sh->offset = getOffset(s, context);
    /* p_vaddr = */ getAddress(s, context);
    /* p_paddr = */ getAddress(s, context);
    sh->filesz = getWord(s, context);
    sh->memsz = getWord(s, context);
}

class ElfMapper
{
public:
    ElfMapper(const ElfReader *reader) : file(reader->m_binary) {}

    bool map()
    {
        if (!file.open(QIODevice::ReadOnly))
            return false;

        fdlen = file.size();
        ustart = file.map(0, fdlen);
        if (ustart == 0) {
            // Try reading the data into memory instead.
            raw = file.readAll();
            start = raw.constData();
            fdlen = raw.size();
        }
        return true;
    }

public:
    QFile file;
    QByteArray raw;
    union { const char *start; const uchar *ustart; };
    quint64 fdlen;
};

ElfReader::ElfReader(const QString &binary)
    : m_binary(binary)
{
}

ElfData ElfReader::readHeaders()
{
    readIt();
    return m_elfData;
}

ElfReader::Result ElfReader::readIt()
{
    if (!m_elfData.sectionHeaders.isEmpty())
        return Ok;
    if (!m_elfData.programHeaders.isEmpty())
        return Ok;

    ElfMapper mapper(this);
    if (!mapper.map())
        return Corrupt;

    const quint64 fdlen = mapper.fdlen;

    if (fdlen < 64) {
        m_errorString = QLibrary::tr("'%1' is not an ELF object (%2)")
            .arg(m_binary).arg(QLatin1String("file too small"));
        return NotElf;
    }

    if (strncmp(mapper.start, "\177ELF", 4) != 0) {
        m_errorString = QLibrary::tr("'%1' is not an ELF object")
                .arg(m_binary);
        return NotElf;
    }

    // 32 or 64 bit
    m_elfData.elfclass = ElfClass(mapper.start[4]);
    const bool is64Bit = m_elfData.elfclass == Elf_ELFCLASS64;
    if (m_elfData.elfclass != Elf_ELFCLASS32 && m_elfData.elfclass != Elf_ELFCLASS64) {
        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
            .arg(m_binary).arg(QLatin1String("odd cpu architecture"));
        return Corrupt;
    }

    // int bits = (data[4] << 5);
    // If you remove this check to read ELF objects of a different arch,
    // please make sure you modify the typedefs
    // to match the _plugin_ architecture.
    // if ((sizeof(void*) == 4 && bits != 32)
    //     || (sizeof(void*) == 8 && bits != 64)) {
    //     if (errorString)
    //         *errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
    //         .arg(m_binary).arg(QLatin1String("wrong cpu architecture"));
    //     return Corrupt;
    // }

    // Read Endianess.
    m_elfData.endian = ElfEndian(mapper.ustart[5]);
    if (m_elfData.endian != Elf_ELFDATA2LSB && m_elfData.endian != Elf_ELFDATA2MSB) {
        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
            .arg(m_binary).arg(QLatin1String("odd endianess"));
        return Corrupt;
    }

    const uchar *data = mapper.ustart + 16; // e_ident
    m_elfData.elftype    = ElfType(getHalfWord(data, m_elfData));
    m_elfData.elfmachine = ElfMachine(getHalfWord(data, m_elfData));
    /* e_version = */   getWord(data, m_elfData);
    m_elfData.entryPoint = getAddress(data, m_elfData);

    quint64 e_phoff   = getOffset(data, m_elfData);
    quint64 e_shoff   = getOffset(data, m_elfData);
    /* e_flags = */     getWord(data, m_elfData);

    quint32 e_shsize  = getHalfWord(data, m_elfData);

    if (e_shsize > fdlen) {
        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
            .arg(m_binary).arg(QLatin1String("unexpected e_shsize"));
        return Corrupt;
    }

    quint32 e_phentsize = getHalfWord(data, m_elfData);
    QTC_CHECK(e_phentsize == (is64Bit ? 44 : 32));
    quint32 e_phnum     = getHalfWord(data, m_elfData);

    quint32 e_shentsize = getHalfWord(data, m_elfData);

    if (e_shentsize % 4) {
        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
            .arg(m_binary).arg(QLatin1String("unexpected e_shentsize"));
        return Corrupt;
    }

    quint32 e_shnum     = getHalfWord(data, m_elfData);
    quint32 e_shtrndx   = getHalfWord(data, m_elfData);
    QTC_CHECK(data == mapper.ustart + (is64Bit ? 58 : 52));

    if (quint64(e_shnum) * e_shentsize > fdlen) {
        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
            .arg(m_binary)
            .arg(QLatin1String("announced %2 sections, each %3 bytes, exceed file size"))
            .arg(e_shnum).arg(e_shentsize);
        return Corrupt;
    }

    quint64 soff = e_shoff + e_shentsize * e_shtrndx;

//    if ((soff + e_shentsize) > fdlen || soff % 4 || soff == 0) {
//        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
//           .arg(m_binary)
//           .arg(QLatin1String("shstrtab section header seems to be at %1"))
//           .arg(QString::number(soff, 16));
//        return Corrupt;
//    }

    if (e_shoff) {
        ElfSectionHeader strtab;
        parseSectionHeader(mapper.ustart + soff, &strtab, m_elfData);
        const quint64 stringTableFileOffset = strtab.offset;

        if (quint32(stringTableFileOffset + e_shentsize) >= fdlen
                || stringTableFileOffset == 0) {
            m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
                .arg(m_binary)
                .arg(QLatin1String("string table seems to be at %1"))
                .arg(QString::number(soff, 16));
            return Corrupt;
        }

        for (int i = 0; i < e_shnum; ++i) {
            const uchar *s = mapper.ustart + e_shoff + i * e_shentsize;
            ElfSectionHeader sh;
            parseSectionHeader(s, &sh, m_elfData);

            if (stringTableFileOffset + sh.index > fdlen) {
                m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
                    .arg(m_binary)
                    .arg(QLatin1String("section name %2 of %3 behind end of file"))
                    .arg(i).arg(e_shnum);
                return Corrupt;
            }

            sh.name = mapper.start + stringTableFileOffset + sh.index;
            if (sh.name == ".gdb_index") {
                m_elfData.symbolsType = FastSymbols;
            } else if (sh.name == ".debug_info") {
                m_elfData.symbolsType = PlainSymbols;
            } else if (sh.name == ".gnu_debuglink") {
                m_elfData.debugLink = QByteArray(mapper.start + sh.offset);
                m_elfData.symbolsType = LinkedSymbols;
            } else if (sh.name == ".note.gnu.build-id") {
                m_elfData.symbolsType = BuildIdSymbols;
                if (sh.size > 16)
                    m_elfData.buildId = QByteArray(mapper.start + sh.offset + 16,
                                                   sh.size - 16).toHex();
            }
            m_elfData.sectionHeaders.append(sh);
        }
    }

    if (e_phoff) {
        for (int i = 0; i < e_phnum; ++i) {
            const uchar *s = mapper.ustart + e_phoff + i * e_phentsize;
            ElfProgramHeader ph;
            parseProgramHeader(s, &ph, m_elfData);
            m_elfData.programHeaders.append(ph);
        }
    }
    return Ok;
}

QByteArray ElfReader::readSection(const QByteArray &name)
{
    readIt();
    int i = m_elfData.indexOf(name);
    if (i == -1)
        return QByteArray();

    ElfMapper mapper(this);
    if (!mapper.map())
        return QByteArray();

    const ElfSectionHeader &section = m_elfData.sectionHeaders.at(i);
    return QByteArray(mapper.start + section.offset, section.size);
}

QByteArray ElfReader::readCoreName(bool *isCore)
{
    *isCore = false;

    readIt();

    ElfMapper mapper(this);
    if (!mapper.map())
        return QByteArray();

    if (m_elfData.elftype != Elf_ET_CORE)
        return QByteArray();

    *isCore = true;

    for (int i = 0, n = m_elfData.sectionHeaders.size(); i != n; ++i)
        if (m_elfData.sectionHeaders.at(i).type == Elf_SHT_NOTE) {
            const ElfSectionHeader &header = m_elfData.sectionHeaders.at(i);
            const char *s = mapper.start + header.offset + 0x40;
            return QByteArray(s);
        }

    for (int i = 0, n = m_elfData.programHeaders.size(); i != n; ++i)
        if (m_elfData.programHeaders.at(i).type == Elf_PT_NOTE) {
            const ElfProgramHeader &header = m_elfData.programHeaders.at(i);
            const char *s = mapper.start + header.offset + 0xec;
            return QByteArray(s);
        }

    return QByteArray();
}

int ElfData::indexOf(const QByteArray &name) const
{
    for (int i = 0, n = sectionHeaders.size(); i != n; ++i)
        if (sectionHeaders.at(i).name == name)
            return i;
    return -1;
}

} // namespace Utils
<commit_msg>Elf reader: Fix asserts for 64 bit hosts.<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "elfreader.h"
#include "qtcassert.h"

#include <QFile>
#include <QLibrary>
#include <QDebug>

namespace Utils {

quint16 getHalfWord(const unsigned char *&s, const ElfData &context)
{
    quint16 res;
    if (context.endian == Elf_ELFDATA2MSB)
        res = qFromBigEndian<quint16>(s);
    else
        res = qFromLittleEndian<quint16>(s);
    s += 2;
    return res;
}

quint32 getWord(const unsigned char *&s, const ElfData &context)
{
    quint32 res;
    if (context.endian == Elf_ELFDATA2MSB)
        res = qFromBigEndian<quint32>(s);
    else
        res = qFromLittleEndian<quint32>(s);
    s += 4;
    return res;
}

quint64 getAddress(const unsigned char *&s, const ElfData &context)
{
    quint64 res;
    if (context.elfclass == Elf_ELFCLASS32) {
        if (context.endian == Elf_ELFDATA2MSB)
            res = qFromBigEndian<quint32>(s);
        else
            res = qFromLittleEndian<quint32>(s);
        s += 4;
    } else {
        if (context.endian == Elf_ELFDATA2MSB)
            res = qFromBigEndian<quint64>(s);
        else
            res = qFromLittleEndian<quint64>(s);
        s += 8;
    }
    return res;
}

quint64 getOffset(const unsigned char *&s, const ElfData &context)
{
    return getAddress(s, context);
}

static void parseSectionHeader(const uchar *s, ElfSectionHeader *sh, const ElfData &context)
{
    sh->index = getWord(s, context);
    sh->type = getWord(s, context);
    sh->flags = getOffset(s, context);
    sh->addr = getAddress(s, context);
    sh->offset = getOffset(s, context);
    sh->size = getOffset(s, context);
}

static void parseProgramHeader(const uchar *s, ElfProgramHeader *sh, const ElfData &context)
{
    sh->type = getWord(s, context);
    sh->offset = getOffset(s, context);
    /* p_vaddr = */ getAddress(s, context);
    /* p_paddr = */ getAddress(s, context);
    sh->filesz = getWord(s, context);
    sh->memsz = getWord(s, context);
}

class ElfMapper
{
public:
    ElfMapper(const ElfReader *reader) : file(reader->m_binary) {}

    bool map()
    {
        if (!file.open(QIODevice::ReadOnly))
            return false;

        fdlen = file.size();
        ustart = file.map(0, fdlen);
        if (ustart == 0) {
            // Try reading the data into memory instead.
            raw = file.readAll();
            start = raw.constData();
            fdlen = raw.size();
        }
        return true;
    }

public:
    QFile file;
    QByteArray raw;
    union { const char *start; const uchar *ustart; };
    quint64 fdlen;
};

ElfReader::ElfReader(const QString &binary)
    : m_binary(binary)
{
}

ElfData ElfReader::readHeaders()
{
    readIt();
    return m_elfData;
}

ElfReader::Result ElfReader::readIt()
{
    if (!m_elfData.sectionHeaders.isEmpty())
        return Ok;
    if (!m_elfData.programHeaders.isEmpty())
        return Ok;

    ElfMapper mapper(this);
    if (!mapper.map())
        return Corrupt;

    const quint64 fdlen = mapper.fdlen;

    if (fdlen < 64) {
        m_errorString = QLibrary::tr("'%1' is not an ELF object (%2)")
            .arg(m_binary).arg(QLatin1String("file too small"));
        return NotElf;
    }

    if (strncmp(mapper.start, "\177ELF", 4) != 0) {
        m_errorString = QLibrary::tr("'%1' is not an ELF object")
                .arg(m_binary);
        return NotElf;
    }

    // 32 or 64 bit
    m_elfData.elfclass = ElfClass(mapper.start[4]);
    const bool is64Bit = m_elfData.elfclass == Elf_ELFCLASS64;
    if (m_elfData.elfclass != Elf_ELFCLASS32 && m_elfData.elfclass != Elf_ELFCLASS64) {
        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
            .arg(m_binary).arg(QLatin1String("odd cpu architecture"));
        return Corrupt;
    }

    // int bits = (data[4] << 5);
    // If you remove this check to read ELF objects of a different arch,
    // please make sure you modify the typedefs
    // to match the _plugin_ architecture.
    // if ((sizeof(void*) == 4 && bits != 32)
    //     || (sizeof(void*) == 8 && bits != 64)) {
    //     if (errorString)
    //         *errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
    //         .arg(m_binary).arg(QLatin1String("wrong cpu architecture"));
    //     return Corrupt;
    // }

    // Read Endianess.
    m_elfData.endian = ElfEndian(mapper.ustart[5]);
    if (m_elfData.endian != Elf_ELFDATA2LSB && m_elfData.endian != Elf_ELFDATA2MSB) {
        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
            .arg(m_binary).arg(QLatin1String("odd endianess"));
        return Corrupt;
    }

    const uchar *data = mapper.ustart + 16; // e_ident
    m_elfData.elftype    = ElfType(getHalfWord(data, m_elfData));
    m_elfData.elfmachine = ElfMachine(getHalfWord(data, m_elfData));
    /* e_version = */   getWord(data, m_elfData);
    m_elfData.entryPoint = getAddress(data, m_elfData);

    quint64 e_phoff   = getOffset(data, m_elfData);
    quint64 e_shoff   = getOffset(data, m_elfData);
    /* e_flags = */     getWord(data, m_elfData);

    quint32 e_shsize  = getHalfWord(data, m_elfData);

    if (e_shsize > fdlen) {
        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
            .arg(m_binary).arg(QLatin1String("unexpected e_shsize"));
        return Corrupt;
    }

    quint32 e_phentsize = getHalfWord(data, m_elfData);
    QTC_CHECK(e_phentsize == (is64Bit ? 56 : 32));
    quint32 e_phnum     = getHalfWord(data, m_elfData);

    quint32 e_shentsize = getHalfWord(data, m_elfData);

    if (e_shentsize % 4) {
        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
            .arg(m_binary).arg(QLatin1String("unexpected e_shentsize"));
        return Corrupt;
    }

    quint32 e_shnum     = getHalfWord(data, m_elfData);
    quint32 e_shtrndx   = getHalfWord(data, m_elfData);
    QTC_CHECK(data == mapper.ustart + (is64Bit ? 64 : 52));

    if (quint64(e_shnum) * e_shentsize > fdlen) {
        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
            .arg(m_binary)
            .arg(QLatin1String("announced %2 sections, each %3 bytes, exceed file size"))
            .arg(e_shnum).arg(e_shentsize);
        return Corrupt;
    }

    quint64 soff = e_shoff + e_shentsize * e_shtrndx;

//    if ((soff + e_shentsize) > fdlen || soff % 4 || soff == 0) {
//        m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
//           .arg(m_binary)
//           .arg(QLatin1String("shstrtab section header seems to be at %1"))
//           .arg(QString::number(soff, 16));
//        return Corrupt;
//    }

    if (e_shoff) {
        ElfSectionHeader strtab;
        parseSectionHeader(mapper.ustart + soff, &strtab, m_elfData);
        const quint64 stringTableFileOffset = strtab.offset;

        if (quint32(stringTableFileOffset + e_shentsize) >= fdlen
                || stringTableFileOffset == 0) {
            m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
                .arg(m_binary)
                .arg(QLatin1String("string table seems to be at %1"))
                .arg(QString::number(soff, 16));
            return Corrupt;
        }

        for (int i = 0; i < e_shnum; ++i) {
            const uchar *s = mapper.ustart + e_shoff + i * e_shentsize;
            ElfSectionHeader sh;
            parseSectionHeader(s, &sh, m_elfData);

            if (stringTableFileOffset + sh.index > fdlen) {
                m_errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
                    .arg(m_binary)
                    .arg(QLatin1String("section name %2 of %3 behind end of file"))
                    .arg(i).arg(e_shnum);
                return Corrupt;
            }

            sh.name = mapper.start + stringTableFileOffset + sh.index;
            if (sh.name == ".gdb_index") {
                m_elfData.symbolsType = FastSymbols;
            } else if (sh.name == ".debug_info") {
                m_elfData.symbolsType = PlainSymbols;
            } else if (sh.name == ".gnu_debuglink") {
                m_elfData.debugLink = QByteArray(mapper.start + sh.offset);
                m_elfData.symbolsType = LinkedSymbols;
            } else if (sh.name == ".note.gnu.build-id") {
                m_elfData.symbolsType = BuildIdSymbols;
                if (sh.size > 16)
                    m_elfData.buildId = QByteArray(mapper.start + sh.offset + 16,
                                                   sh.size - 16).toHex();
            }
            m_elfData.sectionHeaders.append(sh);
        }
    }

    if (e_phoff) {
        for (int i = 0; i < e_phnum; ++i) {
            const uchar *s = mapper.ustart + e_phoff + i * e_phentsize;
            ElfProgramHeader ph;
            parseProgramHeader(s, &ph, m_elfData);
            m_elfData.programHeaders.append(ph);
        }
    }
    return Ok;
}

QByteArray ElfReader::readSection(const QByteArray &name)
{
    readIt();
    int i = m_elfData.indexOf(name);
    if (i == -1)
        return QByteArray();

    ElfMapper mapper(this);
    if (!mapper.map())
        return QByteArray();

    const ElfSectionHeader &section = m_elfData.sectionHeaders.at(i);
    return QByteArray(mapper.start + section.offset, section.size);
}

QByteArray ElfReader::readCoreName(bool *isCore)
{
    *isCore = false;

    readIt();

    ElfMapper mapper(this);
    if (!mapper.map())
        return QByteArray();

    if (m_elfData.elftype != Elf_ET_CORE)
        return QByteArray();

    *isCore = true;

    for (int i = 0, n = m_elfData.sectionHeaders.size(); i != n; ++i)
        if (m_elfData.sectionHeaders.at(i).type == Elf_SHT_NOTE) {
            const ElfSectionHeader &header = m_elfData.sectionHeaders.at(i);
            const char *s = mapper.start + header.offset + 0x40;
            return QByteArray(s);
        }

    for (int i = 0, n = m_elfData.programHeaders.size(); i != n; ++i)
        if (m_elfData.programHeaders.at(i).type == Elf_PT_NOTE) {
            const ElfProgramHeader &header = m_elfData.programHeaders.at(i);
            const char *s = mapper.start + header.offset + 0xec;
            return QByteArray(s);
        }

    return QByteArray();
}

int ElfData::indexOf(const QByteArray &name) const
{
    for (int i = 0, n = sectionHeaders.size(); i != n; ++i)
        if (sectionHeaders.at(i).name == name)
            return i;
    return -1;
}

} // namespace Utils
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2005, 2006, 2007, 2009, 2012 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <deal.II/base/function_parser.h>
#include <deal.II/base/utilities.h>
#include <deal.II/lac/vector.h>

#ifdef HAVE_FUNCTIONPARSER
namespace fparser
{
#  include <fparser.hh>
}
#else

namespace fparser
{
  class FunctionParser
  {};
}

#endif

DEAL_II_NAMESPACE_OPEN

template <int dim>
FunctionParser<dim>::FunctionParser(const unsigned int n_components,
                                    const double       initial_time)
                :
                Function<dim>(n_components, initial_time),
                fp (0)
{
  fp = new fparser::FunctionParser[n_components];
}

template <int dim>
FunctionParser<dim>::~FunctionParser()
{
  delete[] fp;
}

#ifdef HAVE_FUNCTIONPARSER
template <int dim>
void FunctionParser<dim>::initialize (const std::string                   &variables,
                      const std::vector<std::string>      &expressions,
                      const std::map<std::string, double> &constants,
                      const bool time_dependent,
                      const bool use_degrees)
{
    initialize (variables,
                expressions,
                constants,
                std::map< std::string, double >(),
                time_dependent,
                use_degrees);
}

template <int dim>
void FunctionParser<dim>::initialize (const std::string   &variables,
                                      const std::vector<std::string>      &expressions,
                                      const std::map<std::string, double> &constants,
                                      const std::map<std::string, double> &units,
                                      const bool time_dependent,
                                      const bool use_degrees)
{
                                   // We check that the number of
                                   // components of this function
                                   // matches the number of components
                                   // passed in as a vector of
                                   // strings.
  AssertThrow(this->n_components == expressions.size(),
              ExcInvalidExpressionSize(this->n_components,
                                       expressions.size()) );

  for (unsigned int i=0; i<this->n_components; ++i)
    {

                       // Add the various units to
                       // the parser.
        std::map< std::string, double >::const_iterator
            unit = units.begin(),
            endu = units.end();
        for (; unit != endu; ++unit)
        {
            const bool success = fp[i].AddUnit(unit->first, unit->second);
            AssertThrow (success,
                         ExcMessage("Invalid Unit Name [error adding a unit]"));
        }

                                       // Add the various constants to
                                       // the parser.
      std::map< std::string, double >::const_iterator
        constant = constants.begin(),
        endc  = constants.end();
      for(; constant != endc; ++constant)
        {
          const bool success = fp[i].AddConstant(constant->first, constant->second);
          AssertThrow (success, ExcMessage("Invalid Constant Name"));
        }

      const int ret_value = fp[i].Parse(expressions[i],
                                        variables,
                                        use_degrees);
      AssertThrow (ret_value == -1,
                   ExcParseError(ret_value, fp[i].ErrorMsg()));

                                       // The fact that the parser did
                                       // not throw an error does not
                                       // mean that everything went
                                       // ok... we can still have
                                       // problems with the number of
                                       // variables...
    }
/*
TODO: Remove or port to fparser 4.5
                                   // Now we define how many variables
                                   // we expect to read in.  We
                                   // distinguish between two cases:
                                   // Time dependent problems, and not
                                   // time dependent problems. In the
                                   // first case the number of
                                   // variables is given by the
                                   // dimension plus one. In the other
                                   // case, the number of variables is
                                   // equal to the dimension. Once we
                                   // parsed the variables string, if
                                   // none of this is the case, then
                                   // an exception is thrown.
  if (time_dependent)
    n_vars = dim+1;
  else
    n_vars = dim;

                                   // Let's check if the number of
                                   // variables is correct...
  AssertThrow (n_vars == fp[0].NVars(),
               ExcDimensionMismatch(n_vars,fp[0].NVars()));

                                   // Now set the initialization bit.
*/
  initialized = true;
}

template <int dim>
void FunctionParser<dim>::initialize (const std::string &variables,
                                      const std::string &expression,
                                      const std::map<std::string, double> &constants,
                                      const bool time_dependent,
                                      const bool use_degrees)
{
                                   // initialize with the things
                                   // we got.
  initialize (variables,
              Utilities::split_string_list (expression, ';'),
              constants,
              time_dependent,
              use_degrees);
}

template <int dim>
void FunctionParser<dim>::initialize (const std::string &variables,
                      const std::string &expression,
                      const std::map<std::string, double> &constants,
                      const std::map<std::string, double> &units,
                      const bool time_dependent,
                      const bool use_degrees)
{
                   // initialize with the things
                   // we got.
  initialize (variables,
              Utilities::split_string_list (expression, ';'),
              constants,
              units,
              time_dependent,
              use_degrees);
}

template <int dim>
double FunctionParser<dim>::value (const Point<dim>  &p,
                                   const unsigned int component) const
{
  Assert (initialized==true, ExcNotInitialized());
  Assert (component < this->n_components,
          ExcIndexRange(component, 0, this->n_components));

                                   // Statically allocate dim+1
                                   // double variables.
  double vars[dim+1];

  for (unsigned int i=0; i<dim; ++i)
    vars[i] = p(i);

                                   // We need the time variable only
                                   // if the number of variables is
                                   // different from the dimension. In
                                   // this case it can only be dim+1,
                                   // otherwise an exception would
                                   // have already been thrown
  if (dim != n_vars)
    vars[dim] = this->get_time();

  double my_value = fp[component].Eval((double*)vars);

  AssertThrow (fp[component].EvalError() == 0,
               ExcMessage(fp[component].ErrorMsg()));
  return my_value;
}

template <int dim>
void FunctionParser<dim>::vector_value (const Point<dim> &p,
                                        Vector<double>   &values) const
{
  Assert (initialized==true, ExcNotInitialized());
  Assert (values.size() == this->n_components,
          ExcDimensionMismatch (values.size(), this->n_components));

                                   // Statically allocates dim+1
                                   // double variables.
  double vars[dim+1];

  for(unsigned int i=0; i<dim; ++i)
    vars[i] = p(i);

                                   // We need the time variable only
                                   // if the number of variables is
                                   // different from the dimension. In
                                   // this case it can only be dim+1,
                                   // otherwise an exception would
                                   // have already been thrown
  if(dim != n_vars)
    vars[dim] = this->get_time();

  for(unsigned int component = 0; component < this->n_components;
      ++component)
    {
      values(component) = fp[component].Eval((double*)vars);
      AssertThrow(fp[component].EvalError() == 0,
                  ExcMessage(fp[component].ErrorMsg()));
    }
}

#else

template <int dim>
void
FunctionParser<dim>::initialize(const std::string &,
                                const std::vector<std::string> &,
                                const std::map<std::string, double> &,
                                const bool,
                                const bool)
{
  Assert(false, ExcDisabled("parser"));
}

template <int dim>
void
FunctionParser<dim>::initialize(const std::string &,
                                const std::string &,
                                const std::map<std::string, double> &,
                                const bool,
                                const bool)
{
  Assert(false, ExcDisabled("parser"));
}

template <int dim>
double FunctionParser<dim>::value (
  const Point<dim> &, unsigned int) const
{
  Assert(false, ExcDisabled("parser"));
  return 0.;
}

template <int dim>
void FunctionParser<dim>::vector_value (
  const Point<dim>&, Vector<double>&) const
{
  Assert(false, ExcDisabled("parser"));
}

#endif

// Explicit Instantiations.

template class FunctionParser<1>;
template class FunctionParser<2>;
template class FunctionParser<3>;

DEAL_II_NAMESPACE_CLOSE
<commit_msg>Bugfix<commit_after>//---------------------------------------------------------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2005, 2006, 2007, 2009, 2012 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <deal.II/base/function_parser.h>
#include <deal.II/base/utilities.h>
#include <deal.II/lac/vector.h>

#ifdef HAVE_FUNCTIONPARSER
#include <fparser.hh>
namespace fparser
{
  class FunctionParser: public ::FunctionParser
  {};
}
#else

namespace fparser
{
  class FunctionParser
  {};
}

#endif

DEAL_II_NAMESPACE_OPEN

template <int dim>
FunctionParser<dim>::FunctionParser(const unsigned int n_components,
                                    const double       initial_time)
                :
                Function<dim>(n_components, initial_time),
                fp (0)
{
  fp = new fparser::FunctionParser[n_components];
}

template <int dim>
FunctionParser<dim>::~FunctionParser()
{
  delete[] fp;
}

#ifdef HAVE_FUNCTIONPARSER
template <int dim>
void FunctionParser<dim>::initialize (const std::string                   &variables,
                      const std::vector<std::string>      &expressions,
                      const std::map<std::string, double> &constants,
                      const bool time_dependent,
                      const bool use_degrees)
{
    initialize (variables,
                expressions,
                constants,
                std::map< std::string, double >(),
                time_dependent,
                use_degrees);
}

template <int dim>
void FunctionParser<dim>::initialize (const std::string   &variables,
                                      const std::vector<std::string>      &expressions,
                                      const std::map<std::string, double> &constants,
                                      const std::map<std::string, double> &units,
                                      const bool time_dependent,
                                      const bool use_degrees)
{
                                   // We check that the number of
                                   // components of this function
                                   // matches the number of components
                                   // passed in as a vector of
                                   // strings.
  AssertThrow(this->n_components == expressions.size(),
              ExcInvalidExpressionSize(this->n_components,
                                       expressions.size()) );

  for (unsigned int i=0; i<this->n_components; ++i)
    {

                       // Add the various units to
                       // the parser.
        std::map< std::string, double >::const_iterator
            unit = units.begin(),
            endu = units.end();
        for (; unit != endu; ++unit)
        {
            const bool success = fp[i].AddUnit(unit->first, unit->second);
            AssertThrow (success,
                         ExcMessage("Invalid Unit Name [error adding a unit]"));
        }

                                       // Add the various constants to
                                       // the parser.
      std::map< std::string, double >::const_iterator
        constant = constants.begin(),
        endc  = constants.end();
      for(; constant != endc; ++constant)
        {
          const bool success = fp[i].AddConstant(constant->first, constant->second);
          AssertThrow (success, ExcMessage("Invalid Constant Name"));
        }

      const int ret_value = fp[i].Parse(expressions[i],
                                        variables,
                                        use_degrees);
      AssertThrow (ret_value == -1,
                   ExcParseError(ret_value, fp[i].ErrorMsg()));

                                       // The fact that the parser did
                                       // not throw an error does not
                                       // mean that everything went
                                       // ok... we can still have
                                       // problems with the number of
                                       // variables...
    }
/*
TODO: Remove or port to fparser 4.5
                                   // Now we define how many variables
                                   // we expect to read in.  We
                                   // distinguish between two cases:
                                   // Time dependent problems, and not
                                   // time dependent problems. In the
                                   // first case the number of
                                   // variables is given by the
                                   // dimension plus one. In the other
                                   // case, the number of variables is
                                   // equal to the dimension. Once we
                                   // parsed the variables string, if
                                   // none of this is the case, then
                                   // an exception is thrown.
  if (time_dependent)
    n_vars = dim+1;
  else
    n_vars = dim;

                                   // Let's check if the number of
                                   // variables is correct...
  AssertThrow (n_vars == fp[0].NVars(),
               ExcDimensionMismatch(n_vars,fp[0].NVars()));

                                   // Now set the initialization bit.
*/
  initialized = true;
}

template <int dim>
void FunctionParser<dim>::initialize (const std::string &variables,
                                      const std::string &expression,
                                      const std::map<std::string, double> &constants,
                                      const bool time_dependent,
                                      const bool use_degrees)
{
                                   // initialize with the things
                                   // we got.
  initialize (variables,
              Utilities::split_string_list (expression, ';'),
              constants,
              time_dependent,
              use_degrees);
}

template <int dim>
void FunctionParser<dim>::initialize (const std::string &variables,
                      const std::string &expression,
                      const std::map<std::string, double> &constants,
                      const std::map<std::string, double> &units,
                      const bool time_dependent,
                      const bool use_degrees)
{
                   // initialize with the things
                   // we got.
  initialize (variables,
              Utilities::split_string_list (expression, ';'),
              constants,
              units,
              time_dependent,
              use_degrees);
}

template <int dim>
double FunctionParser<dim>::value (const Point<dim>  &p,
                                   const unsigned int component) const
{
  Assert (initialized==true, ExcNotInitialized());
  Assert (component < this->n_components,
          ExcIndexRange(component, 0, this->n_components));

                                   // Statically allocate dim+1
                                   // double variables.
  double vars[dim+1];

  for (unsigned int i=0; i<dim; ++i)
    vars[i] = p(i);

                                   // We need the time variable only
                                   // if the number of variables is
                                   // different from the dimension. In
                                   // this case it can only be dim+1,
                                   // otherwise an exception would
                                   // have already been thrown
  if (dim != n_vars)
    vars[dim] = this->get_time();

  double my_value = fp[component].Eval((double*)vars);

  AssertThrow (fp[component].EvalError() == 0,
               ExcMessage(fp[component].ErrorMsg()));
  return my_value;
}

template <int dim>
void FunctionParser<dim>::vector_value (const Point<dim> &p,
                                        Vector<double>   &values) const
{
  Assert (initialized==true, ExcNotInitialized());
  Assert (values.size() == this->n_components,
          ExcDimensionMismatch (values.size(), this->n_components));

                                   // Statically allocates dim+1
                                   // double variables.
  double vars[dim+1];

  for(unsigned int i=0; i<dim; ++i)
    vars[i] = p(i);

                                   // We need the time variable only
                                   // if the number of variables is
                                   // different from the dimension. In
                                   // this case it can only be dim+1,
                                   // otherwise an exception would
                                   // have already been thrown
  if(dim != n_vars)
    vars[dim] = this->get_time();

  for(unsigned int component = 0; component < this->n_components;
      ++component)
    {
      values(component) = fp[component].Eval((double*)vars);
      AssertThrow(fp[component].EvalError() == 0,
                  ExcMessage(fp[component].ErrorMsg()));
    }
}

#else

template <int dim>
void
FunctionParser<dim>::initialize(const std::string &,
                                const std::vector<std::string> &,
                                const std::map<std::string, double> &,
                                const bool,
                                const bool)
{
  Assert(false, ExcDisabled("parser"));
}

template <int dim>
void
FunctionParser<dim>::initialize(const std::string &,
                                const std::string &,
                                const std::map<std::string, double> &,
                                const bool,
                                const bool)
{
  Assert(false, ExcDisabled("parser"));
}

template <int dim>
double FunctionParser<dim>::value (
  const Point<dim> &, unsigned int) const
{
  Assert(false, ExcDisabled("parser"));
  return 0.;
}

template <int dim>
void FunctionParser<dim>::vector_value (
  const Point<dim>&, Vector<double>&) const
{
  Assert(false, ExcDisabled("parser"));
}

#endif

// Explicit Instantiations.

template class FunctionParser<1>;
template class FunctionParser<2>;
template class FunctionParser<3>;

DEAL_II_NAMESPACE_CLOSE
<|endoftext|>