<commit_before>// @(#)root/base:$Name:  $:$Id: TAttPad.cxx,v 1.2 2000/11/21 16:26:48 brun Exp $
// Author: Rene Brun   04/01/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Strlen.h"
#include "TAttPad.h"
#include "TBuffer.h"
#include "TStyle.h"
#include "TClass.h"

ClassImp(TAttPad)

//______________________________________________________________________________
//
//  Manages default Pad attributes. Referenced by TStyle.
//

//______________________________________________________________________________
TAttPad::TAttPad()
{
   ResetAttPad();
}

//______________________________________________________________________________
TAttPad::~TAttPad()
{

}

//______________________________________________________________________________
void TAttPad::Copy(TAttPad &attpad)
{
   attpad.fLeftMargin   = fLeftMargin;
   attpad.fRightMargin  = fRightMargin;
   attpad.fBottomMargin = fBottomMargin;
   attpad.fTopMargin    = fTopMargin;
   attpad.fXfile   = fXfile;
   attpad.fYfile   = fYfile;
   attpad.fAfile   = fAfile;
   attpad.fXstat   = fXstat;
   attpad.fYstat   = fYstat;
   attpad.fAstat   = fAstat;
   attpad.fFrameFillColor = fFrameFillColor;
   attpad.fFrameFillStyle = fFrameFillStyle;
   attpad.fFrameLineColor = fFrameLineColor;
   attpad.fFrameLineStyle = fFrameLineStyle;
   attpad.fFrameLineWidth = fFrameLineWidth;
   attpad.fFrameBorderSize= fFrameBorderSize;
   attpad.fFrameBorderMode= fFrameBorderMode;
}

//______________________________________________________________________________
void TAttPad::Print(Option_t *) const
{
}

//______________________________________________________________________________
void TAttPad::ResetAttPad(Option_t *)
{
   fLeftMargin   = gStyle->GetPadLeftMargin();
   fRightMargin  = gStyle->GetPadRightMargin();
   fBottomMargin = gStyle->GetPadBottomMargin();
   fTopMargin    = gStyle->GetPadTopMargin();
   fXfile  = 2;
   fYfile  = 2;
   fAfile  = 1;
   fXstat  = 0.99;
   fYstat  = 0.99;
   fAstat  = 2;
   fFrameLineColor = gStyle->GetFrameLineColor();
   fFrameFillColor = gStyle->GetFrameFillColor();
   fFrameFillStyle = gStyle->GetFrameFillStyle();
   fFrameLineStyle = gStyle->GetFrameLineStyle();
   fFrameLineWidth = gStyle->GetFrameLineWidth();
   fFrameBorderSize= gStyle->GetFrameBorderSize();
   fFrameBorderMode= gStyle->GetFrameBorderMode();
}

//______________________________________________________________________________
void TAttPad::SetBottomMargin(Float_t margin)
{
//*-*-*-*-*-*-*-*-*Set Pad bottom margin in per cent of the pad height*-*-*-*
//*-*              ===================================================
   if (margin <= 0 || margin >=1) margin = 0.1;
   if (margin + fTopMargin >= 1) return;
   fBottomMargin = margin;
}

//______________________________________________________________________________
void TAttPad::SetLeftMargin(Float_t margin)
{
//*-*-*-*-*-*-*-*-*Set Pad left margin in per cent of the pad width*-*-*-*-*
//*-*              ================================================
   if (margin <= 0 || margin >=1) margin = 0.1;
   if (margin + fRightMargin >= 1) return;
   fLeftMargin = margin;
}

//______________________________________________________________________________
void TAttPad::SetRightMargin(Float_t margin)
{
//*-*-*-*-*-*-*-*-*Set Pad right margin in per cent of the pad width*-*-*-*-*
//*-*              =================================================
   if (margin <= 0 || margin >=1) margin = 0.1;
   if (margin + fLeftMargin >= 1) return;
   fRightMargin = margin;
}

//______________________________________________________________________________
void TAttPad::SetTopMargin(Float_t margin)
{
//*-*-*-*-*-*-*-*-*Set Pad top margin in per cent of the pad height*-*-*-*-*
//*-*              ================================================
   if (margin <= 0 || margin >=1) margin = 0.1;
   if (margin + fBottomMargin >= 1) return;
   fTopMargin = margin;
}

//______________________________________________________________________________
void TAttPad::Streamer(TBuffer &R__b)
{
   // Stream an object of class TAttPad.

   if (R__b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      if (R__v > 2) {
         TAttPad::Class()->ReadBuffer(R__b, this, R__v, R__s, R__c);
         return;
      }
      //====process old versions before automatic schema evolution
      R__b >> fLeftMargin;
      R__b >> fRightMargin;
      R__b >> fBottomMargin;
      R__b >> fTopMargin;
      R__b >> fXfile;
      R__b >> fYfile;
      R__b >> fAfile;
      R__b >> fXstat;
      R__b >> fYstat;
      R__b >> fAstat;
      if (R__v > 1) {
         R__b >> fFrameFillColor;
         R__b >> fFrameLineColor;
         R__b >> fFrameFillStyle;
         R__b >> fFrameLineStyle;
         R__b >> fFrameLineWidth;
         R__b >> fFrameBorderSize;
         R__b >> fFrameBorderMode;
      }
      //====end of old versions

   } else {
      TAttPad::Class()->WriteBuffer(R__b,this);
   }
}
<commit_msg>Add possibility to set the pad margins equal to 0.<commit_after>// @(#)root/base:$Name:  $:$Id: TAttPad.cxx,v 1.3 2000/12/13 15:13:45 brun Exp $
// Author: Rene Brun   04/01/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Strlen.h"
#include "TAttPad.h"
#include "TBuffer.h"
#include "TStyle.h"
#include "TClass.h"

ClassImp(TAttPad)

//______________________________________________________________________________
//
//  Manages default Pad attributes. Referenced by TStyle.
//

//______________________________________________________________________________
TAttPad::TAttPad()
{
   ResetAttPad();
}

//______________________________________________________________________________
TAttPad::~TAttPad()
{

}

//______________________________________________________________________________
void TAttPad::Copy(TAttPad &attpad)
{
   attpad.fLeftMargin   = fLeftMargin;
   attpad.fRightMargin  = fRightMargin;
   attpad.fBottomMargin = fBottomMargin;
   attpad.fTopMargin    = fTopMargin;
   attpad.fXfile   = fXfile;
   attpad.fYfile   = fYfile;
   attpad.fAfile   = fAfile;
   attpad.fXstat   = fXstat;
   attpad.fYstat   = fYstat;
   attpad.fAstat   = fAstat;
   attpad.fFrameFillColor = fFrameFillColor;
   attpad.fFrameFillStyle = fFrameFillStyle;
   attpad.fFrameLineColor = fFrameLineColor;
   attpad.fFrameLineStyle = fFrameLineStyle;
   attpad.fFrameLineWidth = fFrameLineWidth;
   attpad.fFrameBorderSize= fFrameBorderSize;
   attpad.fFrameBorderMode= fFrameBorderMode;
}

//______________________________________________________________________________
void TAttPad::Print(Option_t *) const
{
}

//______________________________________________________________________________
void TAttPad::ResetAttPad(Option_t *)
{
   fLeftMargin   = gStyle->GetPadLeftMargin();
   fRightMargin  = gStyle->GetPadRightMargin();
   fBottomMargin = gStyle->GetPadBottomMargin();
   fTopMargin    = gStyle->GetPadTopMargin();
   fXfile  = 2;
   fYfile  = 2;
   fAfile  = 1;
   fXstat  = 0.99;
   fYstat  = 0.99;
   fAstat  = 2;
   fFrameLineColor = gStyle->GetFrameLineColor();
   fFrameFillColor = gStyle->GetFrameFillColor();
   fFrameFillStyle = gStyle->GetFrameFillStyle();
   fFrameLineStyle = gStyle->GetFrameLineStyle();
   fFrameLineWidth = gStyle->GetFrameLineWidth();
   fFrameBorderSize= gStyle->GetFrameBorderSize();
   fFrameBorderMode= gStyle->GetFrameBorderMode();
}

//______________________________________________________________________________
void TAttPad::SetBottomMargin(Float_t margin)
{
//*-*-*-*-*-*-*-*-*Set Pad bottom margin in per cent of the pad height*-*-*-*
//*-*              ===================================================
   if (margin < 0 || margin >=1) margin = 0.1;
   if (margin + fTopMargin >= 1) return;
   fBottomMargin = margin;
}

//______________________________________________________________________________
void TAttPad::SetLeftMargin(Float_t margin)
{
//*-*-*-*-*-*-*-*-*Set Pad left margin in per cent of the pad width*-*-*-*-*
//*-*              ================================================
   if (margin < 0 || margin >=1) margin = 0.1;
   if (margin + fRightMargin >= 1) return;
   fLeftMargin = margin;
}

//______________________________________________________________________________
void TAttPad::SetRightMargin(Float_t margin)
{
//*-*-*-*-*-*-*-*-*Set Pad right margin in per cent of the pad width*-*-*-*-*
//*-*              =================================================
   if (margin < 0 || margin >=1) margin = 0.1;
   if (margin + fLeftMargin >= 1) return;
   fRightMargin = margin;
}

//______________________________________________________________________________
void TAttPad::SetTopMargin(Float_t margin)
{
//*-*-*-*-*-*-*-*-*Set Pad top margin in per cent of the pad height*-*-*-*-*
//*-*              ================================================
   if (margin < 0 || margin >=1) margin = 0.1;
   if (margin + fBottomMargin >= 1) return;
   fTopMargin = margin;
}

//______________________________________________________________________________
void TAttPad::Streamer(TBuffer &R__b)
{
   // Stream an object of class TAttPad.

   if (R__b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      if (R__v > 2) {
         TAttPad::Class()->ReadBuffer(R__b, this, R__v, R__s, R__c);
         return;
      }
      //====process old versions before automatic schema evolution
      R__b >> fLeftMargin;
      R__b >> fRightMargin;
      R__b >> fBottomMargin;
      R__b >> fTopMargin;
      R__b >> fXfile;
      R__b >> fYfile;
      R__b >> fAfile;
      R__b >> fXstat;
      R__b >> fYstat;
      R__b >> fAstat;
      if (R__v > 1) {
         R__b >> fFrameFillColor;
         R__b >> fFrameLineColor;
         R__b >> fFrameFillStyle;
         R__b >> fFrameLineStyle;
         R__b >> fFrameLineWidth;
         R__b >> fFrameBorderSize;
         R__b >> fFrameBorderMode;
      }
      //====end of old versions

   } else {
      TAttPad::Class()->WriteBuffer(R__b,this);
   }
}
<|endoftext|>


<commit_before><commit_msg>List instruction/address-mode pairings in CPU::execute<commit_after><|endoftext|>


<commit_before>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/syslog/global.h>
#include <lib/trace-provider/provider.h>
#include <lib/trace/event.h>

#include "dart_runner.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
#include "logging.h"
#include "runtime/dart/utils/files.h"
#include "runtime/dart/utils/tempfs.h"
#include "third_party/dart/runtime/include/dart_api.h"

#if !defined(DART_PRODUCT)
// Register native symbol information for the Dart VM's profiler.
static void RegisterProfilerSymbols(const char* symbols_path,
                                    const char* dso_name) {
  std::string* symbols = new std::string();
  if (dart_utils::ReadFileToString(symbols_path, symbols)) {
    Dart_AddSymbols(dso_name, symbols->data(), symbols->size());
  } else {
    FML_LOG(ERROR) << "Failed to load " << symbols_path;
    FML_CHECK(false);
  }
}
#endif  // !defined(DART_PRODUCT)

int main(int argc, const char** argv) {
  fx_log_init();
  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);

  std::unique_ptr<trace::TraceProviderWithFdio> provider;
  {
    bool already_started;
    // Use CreateSynchronously to prevent loss of early events.
    trace::TraceProviderWithFdio::CreateSynchronously(
        loop.dispatcher(), "dart_runner", &provider, &already_started);
  }

#if !defined(DART_PRODUCT)
#if defined(AOT_RUNTIME)
  RegisterProfilerSymbols("pkg/data/dart_aot_runner.dartprofilersymbols", "");
#else
  RegisterProfilerSymbols("pkg/data/dart_jit_runner.dartprofilersymbols", "");
#endif  // defined(AOT_RUNTIME)
#endif  // !defined(DART_PRODUCT)

  dart_utils::RunnerTemp runner_temp;
  dart_runner::DartRunner runner;
  loop.Run();
  return 0;
}
<commit_msg>Eliminate fx_log_init call (#17622)<commit_after>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/syslog/global.h>
#include <lib/trace-provider/provider.h>
#include <lib/trace/event.h>

#include "dart_runner.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
#include "logging.h"
#include "runtime/dart/utils/files.h"
#include "runtime/dart/utils/tempfs.h"
#include "third_party/dart/runtime/include/dart_api.h"

#if !defined(DART_PRODUCT)
// Register native symbol information for the Dart VM's profiler.
static void RegisterProfilerSymbols(const char* symbols_path,
                                    const char* dso_name) {
  std::string* symbols = new std::string();
  if (dart_utils::ReadFileToString(symbols_path, symbols)) {
    Dart_AddSymbols(dso_name, symbols->data(), symbols->size());
  } else {
    FML_LOG(ERROR) << "Failed to load " << symbols_path;
    FML_CHECK(false);
  }
}
#endif  // !defined(DART_PRODUCT)

int main(int argc, const char** argv) {
  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);

  std::unique_ptr<trace::TraceProviderWithFdio> provider;
  {
    bool already_started;
    // Use CreateSynchronously to prevent loss of early events.
    trace::TraceProviderWithFdio::CreateSynchronously(
        loop.dispatcher(), "dart_runner", &provider, &already_started);
  }

#if !defined(DART_PRODUCT)
#if defined(AOT_RUNTIME)
  RegisterProfilerSymbols("pkg/data/dart_aot_runner.dartprofilersymbols", "");
#else
  RegisterProfilerSymbols("pkg/data/dart_jit_runner.dartprofilersymbols", "");
#endif  // defined(AOT_RUNTIME)
#endif  // !defined(DART_PRODUCT)

  dart_utils::RunnerTemp runner_temp;
  dart_runner::DartRunner runner;
  loop.Run();
  return 0;
}
<|endoftext|>


<commit_before>/*
  Handles parsing scenario file and translating it into a scenario structure.
  Secretly sub-contracts out parsing of flightplans
*/
#include <string>
#include <vector>

// This ugly construct is to check for file modification time
#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
#include <unistd.h>
#endif

#ifdef WIN32
#define stat _stat
#endif

namespace sim
{

const uint16_t
  ScnNoChange           = 0b000000,
  ScnLabelsChange       = 0b000001,
  ScnNeedsFullRecompute = 0b000010,
  ScnNeedsPartRecompute = 0b000100
  // More as needed
;

struct ScenarioChanges
{
  uint16_t   type_of_change;
  double     recompute_from;
};

struct Scenario
{
  std::string                   main_file_name
                                        , name
                                 , description
  ;
  std::vector<std::string>        orrery_files
                           , flight_plan_files
  ;
  double                              start_jd
                                     , stop_jd
                                     , step_jd
  ;

  time_t scenario_last_modified;
  // There may be several files making up a scenario. After we load a
  // scenario, we set this to be the latest modification time
  // of all files loaded. The next time we check, if we find that any of the
  // files has a modification time more recent than this, we reload the
  // scenario

  ScenarioChanges scenario_changes;
  // This is filled out by the difference function and indicates what changed
  // when we reloaded the scenario

  bool         valid_scenario;
  std::string   error_message;

  // Scenario() { valid_scenario = false; }
  Scenario( std::string fname );

  bool is_valid() { return valid_scenario; }
  bool requires_recompute()
  {
    return
      scenario_changes.type_of_change &
      ( ScnNeedsFullRecompute | ScnNeedsPartRecompute );
  }

  time_t fetch_scenario_modification_time();
  // Check all scenario files and give us the most recently modified time

  void verify_program_is_sorted();
  // The program must be sorted. We could easily sort it internally, but we
  // choose to be explicit about it and warn the user to fix the arrangement
  // it's possible that out of order statements in a flight plan indicates
  // a planning error

  void load();
  // Load and parse scenario file and included flight plan files

  void reload_changes();
  // If files on disk have changed, load and work out diffs to current scenario

  void load_main_file();
  // Load and parse main scenario file.

  void load_flight_plan();
  // Load and parse flight plan file.

  template<class T>
  void copy_new_params_and_diff( T& old, T _new, uint16_t type_of_change );

};

} // namespace sim<commit_msg>need the default constructor<commit_after>/*
  Handles parsing scenario file and translating it into a scenario structure.
  Secretly sub-contracts out parsing of flightplans
*/
#include <string>
#include <vector>

// This ugly construct is to check for file modification time
#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
#include <unistd.h>
#endif

#ifdef WIN32
#define stat _stat
#endif

namespace sim
{

const uint16_t
  ScnNoChange           = 0b000000,
  ScnLabelsChange       = 0b000001,
  ScnNeedsFullRecompute = 0b000010,
  ScnNeedsPartRecompute = 0b000100
  // More as needed
;

struct ScenarioChanges
{
  uint16_t   type_of_change;
  double     recompute_from;
};

struct Scenario
{
  std::string                   main_file_name
                                        , name
                                 , description
  ;
  std::vector<std::string>        orrery_files
                           , flight_plan_files
  ;
  double                              start_jd
                                     , stop_jd
                                     , step_jd
  ;

  time_t scenario_last_modified;
  // There may be several files making up a scenario. After we load a
  // scenario, we set this to be the latest modification time
  // of all files loaded. The next time we check, if we find that any of the
  // files has a modification time more recent than this, we reload the
  // scenario

  ScenarioChanges scenario_changes;
  // This is filled out by the difference function and indicates what changed
  // when we reloaded the scenario

  bool         valid_scenario;
  std::string   error_message;

  Scenario() { valid_scenario = false; }
  Scenario( std::string fname );

  bool is_valid() { return valid_scenario; }
  bool requires_recompute()
  {
    return
      scenario_changes.type_of_change &
      ( ScnNeedsFullRecompute | ScnNeedsPartRecompute );
  }

  time_t fetch_scenario_modification_time();
  // Check all scenario files and give us the most recently modified time

  void verify_program_is_sorted();
  // The program must be sorted. We could easily sort it internally, but we
  // choose to be explicit about it and warn the user to fix the arrangement
  // it's possible that out of order statements in a flight plan indicates
  // a planning error

  void load();
  // Load and parse scenario file and included flight plan files

  void reload_changes();
  // If files on disk have changed, load and work out diffs to current scenario

  void load_main_file();
  // Load and parse main scenario file.

  void load_flight_plan();
  // Load and parse flight plan file.

  template<class T>
  void copy_new_params_and_diff( T& old, T _new, uint16_t type_of_change );

};

} // namespace sim<|endoftext|>


<commit_before><commit_msg>Use an index macro in tet_grad_shape()<commit_after><|endoftext|>


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

#include <memory>

#include "scheduler.h"

#include "log.h"         // for L_*
#include "utils.h"       // for time_point_to_ullong, format_string

#ifndef L_SCHEDULER
#define L_SCHEDULER_DEFINED
#define L_SCHEDULER(args...)
#endif

ScheduledTask::ScheduledTask(std::chrono::time_point<std::chrono::system_clock> created_at_)
	: wakeup_time(0),
	  created_at(time_point_to_ullong(created_at_)),
	  cleared_at(0) { }

bool
ScheduledTask::clear()
{
	unsigned long long c = 0;
	return cleared_at.compare_exchange_strong(c, time_point_to_ullong(std::chrono::system_clock::now()));
}

std::string
ScheduledTask::__repr__(const std::string& name) const
{
	return format_string("<%s at %p>",
		name.c_str(),
		this
	);
}

SchedulerQueue::SchedulerQueue()
	: ctx(now()),
	  cctx(now()) { }

TaskType
SchedulerQueue::peep(unsigned long long current_key)
{
	ctx.op = StashContext::Operation::peep;
	ctx.cur_key = ctx.atom_cur_key.load();
	ctx.current_key = current_key;
	TaskType task;
	queue.next(ctx, &task);
	return task;
}

TaskType
SchedulerQueue::walk()
{
	ctx.op = StashContext::Operation::walk;
	ctx.cur_key = ctx.atom_cur_key.load();
	ctx.current_key = time_point_to_ullong(std::chrono::system_clock::now());
	TaskType task;
	queue.next(ctx, &task);
	return task;
}

void
SchedulerQueue::clean_checkpoint()
{
	auto cur_key = ctx.atom_cur_key.load();
	if (cur_key < cctx.atom_cur_key.load()) {
		cctx.atom_cur_key = cur_key;
	}
	cctx.atom_end_key = ctx.atom_end_key.load();
}

void
SchedulerQueue::clean()
{
	cctx.op = StashContext::Operation::clean;
	cctx.cur_key = cctx.atom_cur_key.load();
	cctx.current_key = time_point_to_ullong(std::chrono::system_clock::now() - 1s);
	TaskType task;
	queue.next(cctx, &task);
}

void
SchedulerQueue::add(const TaskType& task, unsigned long long key)
{
	queue.add(ctx, key, task);
}

Scheduler::Scheduler(const std::string& name_)
	: name(name_),
	  running(-1),
	  inner_thread(&Scheduler::run, this) { }

Scheduler::Scheduler(const std::string& name_, const std::string format, size_t num_threads)
	: thread_pool(std::make_unique<ThreadPool<>>(format, num_threads)),
	  name(name_),
	  running(-1),
	  inner_thread(&Scheduler::run, this) { }

Scheduler::~Scheduler()
{
	finish(1);
}

size_t
Scheduler::running_size()
{
	if (thread_pool) {
		thread_pool->running_size();
	}
	return 0;
}

void
Scheduler::finish(int wait)
{
	running = wait;
	wakeup_signal.notify_all();

	if (thread_pool) {
		thread_pool->finish();
	}

	if (wait) {
		join();
	}
}

void
Scheduler::join()
{
	try {
		if (inner_thread.joinable()) {
			inner_thread.join();
		}
	} catch (const std::system_error&) { }

	if (thread_pool) {
		thread_pool->join();
		thread_pool.reset();
	}
}

void
Scheduler::add(const TaskType& task, unsigned long long wakeup_time)
{
	if (running != 0) {
		auto now = time_point_to_ullong(std::chrono::system_clock::now());
		if (wakeup_time < now) {
			wakeup_time = now;
		}

		task->wakeup_time = wakeup_time;
		scheduler_queue.add(task, wakeup_time);

		auto next_wakeup_time = atom_next_wakeup_time.load();
		while (next_wakeup_time > wakeup_time && !atom_next_wakeup_time.compare_exchange_weak(next_wakeup_time, wakeup_time));

		if (next_wakeup_time > wakeup_time || next_wakeup_time < now) {
			L_SCHEDULER(this, "Scheduler::" GREEN "NOTIFY" NO_COL " - now:%llu, next_wakeup_time:%llu, wakeup_time:%llu - %s", now, atom_next_wakeup_time.load(), wakeup_time, task ? task->__repr__().c_str() : "");
			{
				std::lock_guard<std::mutex> lk(mtx);
			}
			wakeup_signal.notify_one();
		} else {
			L_SCHEDULER(this, "Scheduler::" BLUE "ADDED" NO_COL " - now:%llu, next_wakeup_time:%llu, wakeup_time:%llu - %s", now, atom_next_wakeup_time.load(), wakeup_time, task ? task->__repr__().c_str() : "");
		}
	}
}

void
Scheduler::add(const TaskType& task, std::chrono::time_point<std::chrono::system_clock> wakeup)
{
	add(task, time_point_to_ullong(wakeup));
}

void
Scheduler::run_one(TaskType& task)
{
	if (*task) {
		if (task->clear()) {
			L_SCHEDULER(this, "Scheduler::" CYAN "RUNNING" NO_COL " - now:%llu, wakeup_time:%llu", time_point_to_ullong(std::chrono::system_clock::now()), task->wakeup_time);
			if (thread_pool) {
				try {
					thread_pool->enqueue(task);
				} catch (const std::logic_error&) { }
			} else {
				task->run();
			}
			return;
		}
	}
	L_SCHEDULER(this, "Scheduler::" RED "ABORTED" NO_COL " - now:%llu, wakeup_time:%llu", time_point_to_ullong(std::chrono::system_clock::now()), task->wakeup_time);
}

void
Scheduler::run()
{
	set_thread_name(name);

	std::unique_lock<std::mutex> lk(mtx);
	lk.unlock();

	auto next_wakeup_time = atom_next_wakeup_time.load();

	while (running != 0) {
		if (--running < 0) {
			running = -1;
		}

		auto now = std::chrono::system_clock::now();
		auto wakeup_time = time_point_to_ullong(now + (running < 0 ? 32s : 100ms));

		TaskType task;

		L_SCHEDULER(this, "Scheduler::" DARK_GREY "PEEPING" NO_COL " - now:%llu, wakeup_time:%llu", time_point_to_ullong(now), wakeup_time);
		if ((task = scheduler_queue.peep(wakeup_time))) {
			if (task) {
				wakeup_time = task->wakeup_time;
				L_SCHEDULER(this, "Scheduler::" BLUE "PEEP" NO_COL " - now:%llu, wakeup_time:%llu  (%s)", time_point_to_ullong(now), wakeup_time, *task ? "valid" : "cleared");
			}
		}

		atom_next_wakeup_time.compare_exchange_strong(next_wakeup_time, wakeup_time);
		while (next_wakeup_time > wakeup_time && !atom_next_wakeup_time.compare_exchange_weak(next_wakeup_time, wakeup_time));

		L_INFO_HOOK_LOG("Scheduler::LOOP", this, "Scheduler::" CYAN "LOOP" NO_COL " - now:%llu, next_wakeup_time:%llu", time_point_to_ullong(now), atom_next_wakeup_time.load());
		lk.lock();
		wakeup_signal.wait_until(lk, time_point_from_ullong(atom_next_wakeup_time.load()));
		lk.unlock();
		L_SCHEDULER(this, "Scheduler::" LIGHT_BLUE "WAKEUP" NO_COL " - now:%llu, wakeup_time:%llu", time_point_to_ullong(std::chrono::system_clock::now()), wakeup_time);

		scheduler_queue.clean_checkpoint();

		while ((task = scheduler_queue.walk())) {
			if (task) {
				run_one(task);
			}
		}

		scheduler_queue.clean();

		if (running >= 0) {
			break;
		}
	}
}

#ifdef L_SCHEDULER_DEFINED
#undef L_SCHEDULER_DEFINED
#undef L_SCHEDULER
#endif
<commit_msg>Scheduler: Avoid race condition<commit_after>/*
 * Copyright (C) 2016 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <memory>

#include "scheduler.h"

#include "log.h"         // for L_*
#include "utils.h"       // for time_point_to_ullong, format_string

#ifndef L_SCHEDULER
#define L_SCHEDULER_DEFINED
#define L_SCHEDULER(args...)
#endif

ScheduledTask::ScheduledTask(std::chrono::time_point<std::chrono::system_clock> created_at_)
	: wakeup_time(0),
	  created_at(time_point_to_ullong(created_at_)),
	  cleared_at(0) { }

bool
ScheduledTask::clear()
{
	unsigned long long c = 0;
	return cleared_at.compare_exchange_strong(c, time_point_to_ullong(std::chrono::system_clock::now()));
}

std::string
ScheduledTask::__repr__(const std::string& name) const
{
	return format_string("<%s at %p>",
		name.c_str(),
		this
	);
}

SchedulerQueue::SchedulerQueue()
	: ctx(now()),
	  cctx(now()) { }

TaskType
SchedulerQueue::peep(unsigned long long current_key)
{
	ctx.op = StashContext::Operation::peep;
	ctx.cur_key = ctx.atom_cur_key.load();
	ctx.current_key = current_key;
	TaskType task;
	queue.next(ctx, &task);
	return task;
}

TaskType
SchedulerQueue::walk()
{
	ctx.op = StashContext::Operation::walk;
	ctx.cur_key = ctx.atom_cur_key.load();
	ctx.current_key = time_point_to_ullong(std::chrono::system_clock::now());
	TaskType task;
	queue.next(ctx, &task);
	return task;
}

void
SchedulerQueue::clean_checkpoint()
{
	auto cur_key = ctx.atom_cur_key.load();
	if (cur_key < cctx.atom_cur_key.load()) {
		cctx.atom_cur_key = cur_key;
	}
	cctx.atom_end_key = ctx.atom_end_key.load();
}

void
SchedulerQueue::clean()
{
	cctx.op = StashContext::Operation::clean;
	cctx.cur_key = cctx.atom_cur_key.load();
	cctx.current_key = time_point_to_ullong(std::chrono::system_clock::now() - 1s);
	TaskType task;
	queue.next(cctx, &task);
}

void
SchedulerQueue::add(const TaskType& task, unsigned long long key)
{
	queue.add(ctx, key, task);
}

Scheduler::Scheduler(const std::string& name_)
	: name(name_),
	  running(-1),
	  inner_thread(&Scheduler::run, this) { }

Scheduler::Scheduler(const std::string& name_, const std::string format, size_t num_threads)
	: thread_pool(std::make_unique<ThreadPool<>>(format, num_threads)),
	  name(name_),
	  running(-1),
	  inner_thread(&Scheduler::run, this) { }

Scheduler::~Scheduler()
{
	finish(1);
}

size_t
Scheduler::running_size()
{
	if (thread_pool) {
		thread_pool->running_size();
	}
	return 0;
}

void
Scheduler::finish(int wait)
{
	running = wait;

	{
		std::lock_guard<std::mutex> lk(mtx);
	}
	wakeup_signal.notify_all();

	if (thread_pool) {
		thread_pool->finish();
	}

	if (wait) {
		join();
	}
}

void
Scheduler::join()
{
	try {
		if (inner_thread.joinable()) {
			inner_thread.join();
		}
	} catch (const std::system_error&) { }

	if (thread_pool) {
		thread_pool->join();
		thread_pool.reset();
	}
}

void
Scheduler::add(const TaskType& task, unsigned long long wakeup_time)
{
	if (running != 0) {
		auto now = time_point_to_ullong(std::chrono::system_clock::now());
		if (wakeup_time < now) {
			wakeup_time = now;
		}

		task->wakeup_time = wakeup_time;
		scheduler_queue.add(task, wakeup_time);

		auto next_wakeup_time = atom_next_wakeup_time.load();
		while (next_wakeup_time > wakeup_time && !atom_next_wakeup_time.compare_exchange_weak(next_wakeup_time, wakeup_time));

		if (next_wakeup_time > wakeup_time || next_wakeup_time < now) {
			L_SCHEDULER(this, "Scheduler::" GREEN "NOTIFY" NO_COL " - now:%llu, next_wakeup_time:%llu, wakeup_time:%llu - %s", now, atom_next_wakeup_time.load(), wakeup_time, task ? task->__repr__().c_str() : "");
			{
				std::lock_guard<std::mutex> lk(mtx);
			}
			wakeup_signal.notify_one();
		} else {
			L_SCHEDULER(this, "Scheduler::" BLUE "ADDED" NO_COL " - now:%llu, next_wakeup_time:%llu, wakeup_time:%llu - %s", now, atom_next_wakeup_time.load(), wakeup_time, task ? task->__repr__().c_str() : "");
		}
	}
}

void
Scheduler::add(const TaskType& task, std::chrono::time_point<std::chrono::system_clock> wakeup)
{
	add(task, time_point_to_ullong(wakeup));
}

void
Scheduler::run_one(TaskType& task)
{
	if (*task) {
		if (task->clear()) {
			L_SCHEDULER(this, "Scheduler::" CYAN "RUNNING" NO_COL " - now:%llu, wakeup_time:%llu", time_point_to_ullong(std::chrono::system_clock::now()), task->wakeup_time);
			if (thread_pool) {
				try {
					thread_pool->enqueue(task);
				} catch (const std::logic_error&) { }
			} else {
				task->run();
			}
			return;
		}
	}
	L_SCHEDULER(this, "Scheduler::" RED "ABORTED" NO_COL " - now:%llu, wakeup_time:%llu", time_point_to_ullong(std::chrono::system_clock::now()), task->wakeup_time);
}

void
Scheduler::run()
{
	set_thread_name(name);

	std::unique_lock<std::mutex> lk(mtx);
	lk.unlock();

	auto next_wakeup_time = atom_next_wakeup_time.load();

	while (running != 0) {
		if (--running < 0) {
			running = -1;
		}

		auto now = std::chrono::system_clock::now();
		auto wakeup_time = time_point_to_ullong(now + (running < 0 ? 32s : 100ms));

		TaskType task;

		L_SCHEDULER(this, "Scheduler::" DARK_GREY "PEEPING" NO_COL " - now:%llu, wakeup_time:%llu", time_point_to_ullong(now), wakeup_time);
		if ((task = scheduler_queue.peep(wakeup_time))) {
			if (task) {
				wakeup_time = task->wakeup_time;
				L_SCHEDULER(this, "Scheduler::" BLUE "PEEP" NO_COL " - now:%llu, wakeup_time:%llu  (%s)", time_point_to_ullong(now), wakeup_time, *task ? "valid" : "cleared");
			}
		}

		atom_next_wakeup_time.compare_exchange_strong(next_wakeup_time, wakeup_time);
		while (next_wakeup_time > wakeup_time && !atom_next_wakeup_time.compare_exchange_weak(next_wakeup_time, wakeup_time));

		L_INFO_HOOK_LOG("Scheduler::LOOP", this, "Scheduler::" CYAN "LOOP" NO_COL " - now:%llu, next_wakeup_time:%llu", time_point_to_ullong(now), atom_next_wakeup_time.load());
		lk.lock();
		wakeup_signal.wait_until(lk, time_point_from_ullong(atom_next_wakeup_time.load()));
		lk.unlock();
		L_SCHEDULER(this, "Scheduler::" LIGHT_BLUE "WAKEUP" NO_COL " - now:%llu, wakeup_time:%llu", time_point_to_ullong(std::chrono::system_clock::now()), wakeup_time);

		scheduler_queue.clean_checkpoint();

		while ((task = scheduler_queue.walk())) {
			if (task) {
				run_one(task);
			}
		}

		scheduler_queue.clean();

		if (running >= 0) {
			break;
		}
	}
}

#ifdef L_SCHEDULER_DEFINED
#undef L_SCHEDULER_DEFINED
#undef L_SCHEDULER
#endif
<|endoftext|>


<commit_before>// Filename: subStreamBuf.cxx
// Created by:  drose (02Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "subStreamBuf.h"
#include "pnotify.h"

#ifndef HAVE_STREAMSIZE
// Some compilers (notably SGI) don't define this for us
typedef int streamsize;
#endif /* HAVE_STREAMSIZE */

static const size_t substream_buffer_size = 4096;

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
SubStreamBuf::
SubStreamBuf() {
  _source = (IStreamWrapper *)NULL;
  _dest = (OStreamWrapper *)NULL;

  // _start is the streampos of the first byte of the SubStream within
  // its parent stream.
  _start = 0;

  // _end is the streampos of the byte following the last byte of the
  // SubStream within its parent stream.  If _end is 0, the SubStream
  // continues to the end of the parent stream, wherever that is.
  _end = 0;

  // _gpos is the streampos of the end of the read buffer (that is,
  // egptr()) within the parent stream.  By comparing _gpos to gpos(),
  // we can determine the actual current file position.  _ppos is the
  // similar pos, for the write pointer.
  _gpos = 0;
  _ppos = 0;

#ifdef PHAVE_IOSTREAM
  _buffer = (char *)PANDA_MALLOC_ARRAY(substream_buffer_size * 2);
  char *ebuf = _buffer + substream_buffer_size * 2;
  char *mbuf = _buffer + substream_buffer_size;
  setg(_buffer, mbuf, mbuf);
  setp(mbuf, ebuf);

#else
  allocate();
  // Chop the buffer in half.  The bottom half goes to the get buffer;
  // the top half goes to the put buffer.
  char *b = base();
  char *t = ebuf();
  char *m = b + (t - b) / 2;
  setg(b, m, m);
  setp(b, m);
#endif
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
SubStreamBuf::
~SubStreamBuf() {
  close();
#ifdef PHAVE_IOSTREAM
  PANDA_FREE_ARRAY(_buffer);
#endif
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::open
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void SubStreamBuf::
open(IStreamWrapper *source, OStreamWrapper *dest, streampos start, streampos end, bool append) {
  _source = source;
  _dest = dest;
  _start = start;
  _end = end;
  _append = append;
  _gpos = _start;
  _ppos = _start;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::close
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void SubStreamBuf::
close() {
  // Make sure the write buffer is flushed.
  sync();

  _source = (IStreamWrapper *)NULL;
  _dest = (OStreamWrapper *)NULL;
  _start = 0;
  _end = 0;

  _gpos = 0;
  _ppos = 0;

  pbump(pbase() - pptr());
  gbump(egptr() - gptr());
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::seekoff
//       Access: Public, Virtual
//  Description: Implements seeking within the stream.
////////////////////////////////////////////////////////////////////
streampos SubStreamBuf::
seekoff(streamoff off, ios_seekdir dir, ios_openmode which) {
  streampos result = -1;

  // Sync the iostream buffer first.
  sync();

  if (which & ios::in) {
    // Determine the current file position.
    size_t n = egptr() - gptr();
    gbump(n);
    _gpos -= n;
    nassertr(_gpos >= 0, EOF);
    streampos cur_pos = _gpos;
    streampos new_pos = cur_pos;

    // Now adjust the data pointer appropriately.
    switch (dir) {
    case ios::beg:
      new_pos = (streampos)off + _start;
      break;

    case ios::cur:
      new_pos = (streampos)((streamoff)cur_pos + off);
      break;

    case ios::end:
      if (_end == (streampos)0) {
        // If the end of the file is unspecified, we have to seek to
        // find it.
        new_pos = _source->seek_gpos_eof() + off;

      } else {
        new_pos = _end + off;
      }
      break;

    default:
      // Shouldn't get here.
      break;
    }

    if (new_pos < _start) {
      // Can't seek before beginning of file.
      return EOF;
    }

    if (_end != (streampos)0 && new_pos > _end) {
      // Can't seek past end of file.
      return EOF;
    }

    _gpos = new_pos;
    nassertr(_gpos >= 0, EOF);
    result = new_pos - _start;
  }

  if (which & ios::out) {
    // Determine the current file position.
    size_t n = pptr() - pbase();
    streampos cur_pos = _ppos + (streamoff)n;
    streampos new_pos = cur_pos;

    // Now adjust the data pointer appropriately.
    switch (dir) {
    case ios::beg:
      new_pos = (streampos)off + _start;
      break;

    case ios::cur:
      new_pos = (streampos)((streamoff)cur_pos + off);
      break;

    case ios::end:
      if (_end == (streampos)0) {
        // If the end of the file is unspecified, we have to seek to
        // find it.
        new_pos = _dest->seek_ppos_eof() + off;

      } else {
        new_pos = _end + off;
      }
      break;

    default:
      // Shouldn't get here.
      break;
    }

    if (new_pos < _start) {
      // Can't seek before beginning of file.
      return EOF;
    }

    if (_end != (streampos)0 && new_pos > _end) {
      // Can't seek past end of file.
      return EOF;
    }

    _ppos = new_pos;
    nassertr(_ppos >= 0, EOF);
    result = new_pos - _start;
  }

  return result;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::seekpos
//       Access: Public, Virtual
//  Description: A variant on seekoff() to implement seeking within a
//               stream.
//
//               The MSDN Library claims that it is only necessary to
//               redefine seekoff(), and not seekpos() as well, as the
//               default implementation of seekpos() is supposed to
//               map to seekoff() exactly as I am doing here; but in
//               fact it must do something else, because seeking
//               didn't work on Windows until I redefined this
//               function as well.
////////////////////////////////////////////////////////////////////
streampos SubStreamBuf::
seekpos(streampos pos, ios_openmode which) {
  return seekoff(pos, ios::beg, which);
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::overflow
//       Access: Protected, Virtual
//  Description: Called by the system ostream implementation when its
//               internal buffer is filled, plus one character.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
overflow(int ch) {
  bool okflag = true;

  size_t n = pptr() - pbase();
  if (n != 0) {
    if (_end != (streampos)0 && _ppos + (streampos)n > _end) {
      // Don't allow reading past the end of the file.
      n = (size_t)(_end - _ppos);
      if (n == 0) {
        // No room.
        return EOF;
      }
    }

    nassertr(_dest != NULL, EOF);
    bool fail = false;
    if (_append) {
      _dest->seek_eof_write(pbase(), n, fail);
    } else {
      _dest->seek_write(_ppos, pbase(), n, fail);
    }
    _ppos += n;
    pbump(-(int)n);
    if (fail) {
      okflag = false;
    }
  }

  if (okflag && ch != EOF) {
    if (pptr() != epptr()) {
      // Store the extra character back in the buffer.
      *(pptr()) = ch;
      pbump(1);
    } else {
      // No room to store ch.
      okflag = false;
    }
  }

  if (!okflag) {
    return EOF;
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::sync
//       Access: Protected, Virtual
//  Description: Called by the system iostream implementation to
//               implement a flush operation.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
sync() {
  size_t n = pptr() - pbase();

  if (n != 0) {
    nassertr(_dest != NULL, EOF);
    bool fail = false;
    if (_append) {
      _dest->seek_eof_write(pbase(), n, fail);
    } else {
      _dest->seek_write(_ppos, pbase(), n, fail);
    }
    _ppos += n;
    pbump(-(int)n);

    if (fail) {
      return EOF;
    }
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::underflow
//       Access: Protected, Virtual
//  Description: Called by the system istream implementation when its
//               internal buffer needs more characters.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
underflow() {
  // Sometimes underflow() is called even if the buffer is not empty.
  if (gptr() >= egptr()) {
    sync();

    // Mark the buffer filled (with buffer_size bytes).
    size_t buffer_size = egptr() - eback();
    gbump(-(int)buffer_size);

    streamsize num_bytes = buffer_size;
    if (_end != (streampos)0 && _gpos + (streampos)num_bytes > _end) {
      // Don't allow reading past the end of the file.
      streamsize new_num_bytes = _end - _gpos;
      if (new_num_bytes == 0) {
        gbump(buffer_size);
        return EOF;
      }

      // We won't be filling the entire buffer.  Fill in only at the
      // end of the buffer.
      size_t delta = num_bytes - new_num_bytes;
      gbump(delta);
      num_bytes = new_num_bytes;
      nassertr(egptr() - gptr() == num_bytes, EOF);
    }

    nassertr(_source != NULL, EOF);
    streamsize read_count;
    bool eof;
    _source->seek_read(_gpos, gptr(), num_bytes, read_count, eof);
    _gpos += read_count;

    if (read_count != num_bytes) {
      // Oops, we didn't read what we thought we would.
      if (read_count == 0) {
        gbump(num_bytes);
        return EOF;
      }

      // Slide what we did read to the top of the buffer.
      nassertr(read_count < num_bytes, EOF);
      size_t delta = num_bytes - read_count;
      memmove(gptr() + delta, gptr(), read_count);
      gbump(delta);
    }
  }

  return (unsigned char)*gptr();
}
<commit_msg>Add missing include<commit_after>// Filename: subStreamBuf.cxx
// Created by:  drose (02Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "subStreamBuf.h"
#include "pnotify.h"
#include "memoryHook.h"

#ifndef HAVE_STREAMSIZE
// Some compilers (notably SGI) don't define this for us
typedef int streamsize;
#endif /* HAVE_STREAMSIZE */

static const size_t substream_buffer_size = 4096;

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
SubStreamBuf::
SubStreamBuf() {
  _source = (IStreamWrapper *)NULL;
  _dest = (OStreamWrapper *)NULL;

  // _start is the streampos of the first byte of the SubStream within
  // its parent stream.
  _start = 0;

  // _end is the streampos of the byte following the last byte of the
  // SubStream within its parent stream.  If _end is 0, the SubStream
  // continues to the end of the parent stream, wherever that is.
  _end = 0;

  // _gpos is the streampos of the end of the read buffer (that is,
  // egptr()) within the parent stream.  By comparing _gpos to gpos(),
  // we can determine the actual current file position.  _ppos is the
  // similar pos, for the write pointer.
  _gpos = 0;
  _ppos = 0;

#ifdef PHAVE_IOSTREAM
  _buffer = (char *)PANDA_MALLOC_ARRAY(substream_buffer_size * 2);
  char *ebuf = _buffer + substream_buffer_size * 2;
  char *mbuf = _buffer + substream_buffer_size;
  setg(_buffer, mbuf, mbuf);
  setp(mbuf, ebuf);

#else
  allocate();
  // Chop the buffer in half.  The bottom half goes to the get buffer;
  // the top half goes to the put buffer.
  char *b = base();
  char *t = ebuf();
  char *m = b + (t - b) / 2;
  setg(b, m, m);
  setp(b, m);
#endif
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
SubStreamBuf::
~SubStreamBuf() {
  close();
#ifdef PHAVE_IOSTREAM
  PANDA_FREE_ARRAY(_buffer);
#endif
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::open
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void SubStreamBuf::
open(IStreamWrapper *source, OStreamWrapper *dest, streampos start, streampos end, bool append) {
  _source = source;
  _dest = dest;
  _start = start;
  _end = end;
  _append = append;
  _gpos = _start;
  _ppos = _start;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::close
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void SubStreamBuf::
close() {
  // Make sure the write buffer is flushed.
  sync();

  _source = (IStreamWrapper *)NULL;
  _dest = (OStreamWrapper *)NULL;
  _start = 0;
  _end = 0;

  _gpos = 0;
  _ppos = 0;

  pbump(pbase() - pptr());
  gbump(egptr() - gptr());
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::seekoff
//       Access: Public, Virtual
//  Description: Implements seeking within the stream.
////////////////////////////////////////////////////////////////////
streampos SubStreamBuf::
seekoff(streamoff off, ios_seekdir dir, ios_openmode which) {
  streampos result = -1;

  // Sync the iostream buffer first.
  sync();

  if (which & ios::in) {
    // Determine the current file position.
    size_t n = egptr() - gptr();
    gbump(n);
    _gpos -= n;
    nassertr(_gpos >= 0, EOF);
    streampos cur_pos = _gpos;
    streampos new_pos = cur_pos;

    // Now adjust the data pointer appropriately.
    switch (dir) {
    case ios::beg:
      new_pos = (streampos)off + _start;
      break;

    case ios::cur:
      new_pos = (streampos)((streamoff)cur_pos + off);
      break;

    case ios::end:
      if (_end == (streampos)0) {
        // If the end of the file is unspecified, we have to seek to
        // find it.
        new_pos = _source->seek_gpos_eof() + off;

      } else {
        new_pos = _end + off;
      }
      break;

    default:
      // Shouldn't get here.
      break;
    }

    if (new_pos < _start) {
      // Can't seek before beginning of file.
      return EOF;
    }

    if (_end != (streampos)0 && new_pos > _end) {
      // Can't seek past end of file.
      return EOF;
    }

    _gpos = new_pos;
    nassertr(_gpos >= 0, EOF);
    result = new_pos - _start;
  }

  if (which & ios::out) {
    // Determine the current file position.
    size_t n = pptr() - pbase();
    streampos cur_pos = _ppos + (streamoff)n;
    streampos new_pos = cur_pos;

    // Now adjust the data pointer appropriately.
    switch (dir) {
    case ios::beg:
      new_pos = (streampos)off + _start;
      break;

    case ios::cur:
      new_pos = (streampos)((streamoff)cur_pos + off);
      break;

    case ios::end:
      if (_end == (streampos)0) {
        // If the end of the file is unspecified, we have to seek to
        // find it.
        new_pos = _dest->seek_ppos_eof() + off;

      } else {
        new_pos = _end + off;
      }
      break;

    default:
      // Shouldn't get here.
      break;
    }

    if (new_pos < _start) {
      // Can't seek before beginning of file.
      return EOF;
    }

    if (_end != (streampos)0 && new_pos > _end) {
      // Can't seek past end of file.
      return EOF;
    }

    _ppos = new_pos;
    nassertr(_ppos >= 0, EOF);
    result = new_pos - _start;
  }

  return result;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::seekpos
//       Access: Public, Virtual
//  Description: A variant on seekoff() to implement seeking within a
//               stream.
//
//               The MSDN Library claims that it is only necessary to
//               redefine seekoff(), and not seekpos() as well, as the
//               default implementation of seekpos() is supposed to
//               map to seekoff() exactly as I am doing here; but in
//               fact it must do something else, because seeking
//               didn't work on Windows until I redefined this
//               function as well.
////////////////////////////////////////////////////////////////////
streampos SubStreamBuf::
seekpos(streampos pos, ios_openmode which) {
  return seekoff(pos, ios::beg, which);
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::overflow
//       Access: Protected, Virtual
//  Description: Called by the system ostream implementation when its
//               internal buffer is filled, plus one character.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
overflow(int ch) {
  bool okflag = true;

  size_t n = pptr() - pbase();
  if (n != 0) {
    if (_end != (streampos)0 && _ppos + (streampos)n > _end) {
      // Don't allow reading past the end of the file.
      n = (size_t)(_end - _ppos);
      if (n == 0) {
        // No room.
        return EOF;
      }
    }

    nassertr(_dest != NULL, EOF);
    bool fail = false;
    if (_append) {
      _dest->seek_eof_write(pbase(), n, fail);
    } else {
      _dest->seek_write(_ppos, pbase(), n, fail);
    }
    _ppos += n;
    pbump(-(int)n);
    if (fail) {
      okflag = false;
    }
  }

  if (okflag && ch != EOF) {
    if (pptr() != epptr()) {
      // Store the extra character back in the buffer.
      *(pptr()) = ch;
      pbump(1);
    } else {
      // No room to store ch.
      okflag = false;
    }
  }

  if (!okflag) {
    return EOF;
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::sync
//       Access: Protected, Virtual
//  Description: Called by the system iostream implementation to
//               implement a flush operation.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
sync() {
  size_t n = pptr() - pbase();

  if (n != 0) {
    nassertr(_dest != NULL, EOF);
    bool fail = false;
    if (_append) {
      _dest->seek_eof_write(pbase(), n, fail);
    } else {
      _dest->seek_write(_ppos, pbase(), n, fail);
    }
    _ppos += n;
    pbump(-(int)n);

    if (fail) {
      return EOF;
    }
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::underflow
//       Access: Protected, Virtual
//  Description: Called by the system istream implementation when its
//               internal buffer needs more characters.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
underflow() {
  // Sometimes underflow() is called even if the buffer is not empty.
  if (gptr() >= egptr()) {
    sync();

    // Mark the buffer filled (with buffer_size bytes).
    size_t buffer_size = egptr() - eback();
    gbump(-(int)buffer_size);

    streamsize num_bytes = buffer_size;
    if (_end != (streampos)0 && _gpos + (streampos)num_bytes > _end) {
      // Don't allow reading past the end of the file.
      streamsize new_num_bytes = _end - _gpos;
      if (new_num_bytes == 0) {
        gbump(buffer_size);
        return EOF;
      }

      // We won't be filling the entire buffer.  Fill in only at the
      // end of the buffer.
      size_t delta = num_bytes - new_num_bytes;
      gbump(delta);
      num_bytes = new_num_bytes;
      nassertr(egptr() - gptr() == num_bytes, EOF);
    }

    nassertr(_source != NULL, EOF);
    streamsize read_count;
    bool eof;
    _source->seek_read(_gpos, gptr(), num_bytes, read_count, eof);
    _gpos += read_count;

    if (read_count != num_bytes) {
      // Oops, we didn't read what we thought we would.
      if (read_count == 0) {
        gbump(num_bytes);
        return EOF;
      }

      // Slide what we did read to the top of the buffer.
      nassertr(read_count < num_bytes, EOF);
      size_t delta = num_bytes - read_count;
      memmove(gptr() + delta, gptr(), read_count);
      gbump(delta);
    }
  }

  return (unsigned char)*gptr();
}
<|endoftext|>


<commit_before>// @(#)root/base:$Name:  $:$Id: TRegexp.cxx,v 1.3 2002/01/20 17:48:45 rdm Exp $
// Author: Fons Rademakers   04/08/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRegexp                                                              //
//                                                                      //
// Regular expression class.                                            //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TRegexp.h"
#include "TString.h"
#include "TError.h"

const unsigned TRegexp::fgMaxpat = 2048;

ClassImp(TRegexp)

//______________________________________________________________________________
TRegexp::TRegexp(const char *re, Bool_t wildcard)
{
   // Create a regular expression from the input string. If wildcard is true
   // then the input string contains a wildcard expression (see MakeWildcard()).

   if (wildcard)
      GenPattern(MakeWildcard(re));
   else
      GenPattern(re);
}

//______________________________________________________________________________
TRegexp::TRegexp(const TString& re)
{
   // Create a regular expression from a TString.

   GenPattern(re.Data());
}

//______________________________________________________________________________
TRegexp::TRegexp(const TRegexp& r)
{
   // Copy ctor.

   CopyPattern(r);
}

//______________________________________________________________________________
TRegexp::~TRegexp()
{
   delete [] fPattern;
}

//______________________________________________________________________________
TRegexp& TRegexp::operator=(const TRegexp& r)
{
   // Assignment operator.

   if (this != &r) {
      delete [] fPattern;
      CopyPattern(r);
   }
   return *this;
}

//______________________________________________________________________________
TRegexp& TRegexp::operator=(const char *str)
{
   // Assignment operator taking a char* and assigning it to a regexp.

   delete [] fPattern;
   GenPattern(str);
   return *this;
}

//______________________________________________________________________________
TRegexp& TRegexp::operator=(const TString &str)
{
   // Assignment operator taking a TString.

   delete [] fPattern;
   GenPattern(str.Data());
   return *this;
}

//______________________________________________________________________________
void TRegexp::GenPattern(const char *str)
{
   // Generate the regular expression pattern.

   fPattern = new Pattern_t[fgMaxpat];
   int error = ::Makepat(str, fPattern, fgMaxpat);
   fStat = (error < 3) ? (EStatVal) error : kToolong;
}

//______________________________________________________________________________
void TRegexp::CopyPattern(const TRegexp& r)
{
   // Copy the regular expression pattern.

   fPattern = new Pattern_t[fgMaxpat];
   memcpy(fPattern, r.fPattern, fgMaxpat * sizeof(Pattern_t));
   fStat = r.fStat;
}

//______________________________________________________________________________
const char *TRegexp::MakeWildcard(const char *re)
{
   // This routine transforms a wildcarding regular expression into
   // a general regular expression used for pattern matching.
   // When using wildcards the regular expression is assumed to be
   // preceded by a "^" (BOL) and terminated by a "$" (EOL). Also, all
   // "*"'s (closures) are assumed to be preceded by a "." (i.e. any character,
   // except "/"'s) and all .'s are escaped (so *.ps is different from *.eps).
   // The special treatment of "/" allows the easy matching of pathnames, e.g.
   // "*.root" will match "aap.root", but not "pipo/aap.root".

   static char buf[fgMaxpat];
   char *s = buf;
   int   len = strlen(re);

   if (!re || !len) return "";

   for (int i = 0; i < len; i++) {
      if (i == 0 && re[i] != '^')
         *s++ = '^';
      if (re[i] == '*') {
         //*s++ = '.';
#ifndef R__WIN32
         strcpy(s, "[a-zA-Z0-9_\\.:-]");
         s += 16;
#else
         strcpy(s, "[a-zA-Z0-9_.-]");
         s += 14;
#endif
      }
      if (re[i] == '.')
         *s++ = '\\';
      *s++ = re[i];
      if (i == len-1 && re[i] != '$')
         *s++ = '$';
   }
   *s = '\0';
   return buf;
}

//______________________________________________________________________________
Ssiz_t TRegexp::Index(const TString& string, Ssiz_t* len, Ssiz_t i) const
{
   // Find the first occurance of the regexp in string and return the position.
   // Len is length of the matched string and i is the offset at which the
   // matching should start.

   if (fStat != kOK)
      Error("TRegexp::Index", "Bad Regular Expression");

   const char* startp;
   const char* s = string.Data();
   Ssiz_t slen = string.Length();
   if (slen < i) return kNPOS;
   const char* endp = ::Matchs(s+i, slen-i, fPattern, &startp);
   if (endp) {
      *len = endp - startp;
      return startp - s;
   } else {
      *len = 0;
      return kNPOS;
   }
}

//______________________________________________________________________________
TRegexp::EStatVal TRegexp::Status()
{
   // Check status of regexp.

   EStatVal temp = fStat;
   fStat = kOK;
   return temp;
}

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TString member functions, put here so the linker will include        //
// them only if regular expressions are used.                           //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
Ssiz_t TString::Index(const TRegexp& r, Ssiz_t start) const
{
   // Find the first occurance of the regexp in string and return the position.
   // Start is the offset at which the search should start.

   Ssiz_t len;
   return r.Index(*this, &len, start); // len not used
}

//______________________________________________________________________________
Ssiz_t TString::Index(const TRegexp& r, Ssiz_t* extent, Ssiz_t start) const
{
   // Find the first occurance of the regexp in string and return the position.
   // Extent is length of the matched string and start is the offset at which
   // the matching should start.

   return r.Index(*this, extent, start);
}

//______________________________________________________________________________
TSubString TString::operator()(const TRegexp& r, Ssiz_t start)
{
   // Return the substring found by applying the regexp starting at start.

   Ssiz_t len;
   Ssiz_t begin = Index(r, &len, start);
   return TSubString(*this, begin, len);
}

//______________________________________________________________________________
TSubString TString::operator()(const TRegexp& r)
{
   // Return the substring found by applying the regexp.

   return (*this)(r,0);
}

//______________________________________________________________________________
TSubString TString::operator()(const TRegexp& r, Ssiz_t start) const
{
   // Return the substring found by applying the regexp starting at start.

   Ssiz_t len;
   Ssiz_t begin = Index(r, &len, start);
   return TSubString(*this, begin, len);
}

//______________________________________________________________________________
TSubString TString::operator()(const TRegexp& r) const
{
   // Return the substring found by applying the regexp.

   return (*this)(r,0);
}

<commit_msg>allow ' ' and ',' as part of a wildcard. Fixes listing of directories containing objects with names like "tree data".<commit_after>// @(#)root/base:$Name:  $:$Id: TRegexp.cxx,v 1.4 2002/01/27 13:39:35 rdm Exp $
// Author: Fons Rademakers   04/08/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRegexp                                                              //
//                                                                      //
// Regular expression class.                                            //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TRegexp.h"
#include "TString.h"
#include "TError.h"

const unsigned TRegexp::fgMaxpat = 2048;

ClassImp(TRegexp)

//______________________________________________________________________________
TRegexp::TRegexp(const char *re, Bool_t wildcard)
{
   // Create a regular expression from the input string. If wildcard is true
   // then the input string contains a wildcard expression (see MakeWildcard()).

   if (wildcard)
      GenPattern(MakeWildcard(re));
   else
      GenPattern(re);
}

//______________________________________________________________________________
TRegexp::TRegexp(const TString& re)
{
   // Create a regular expression from a TString.

   GenPattern(re.Data());
}

//______________________________________________________________________________
TRegexp::TRegexp(const TRegexp& r)
{
   // Copy ctor.

   CopyPattern(r);
}

//______________________________________________________________________________
TRegexp::~TRegexp()
{
   delete [] fPattern;
}

//______________________________________________________________________________
TRegexp& TRegexp::operator=(const TRegexp& r)
{
   // Assignment operator.

   if (this != &r) {
      delete [] fPattern;
      CopyPattern(r);
   }
   return *this;
}

//______________________________________________________________________________
TRegexp& TRegexp::operator=(const char *str)
{
   // Assignment operator taking a char* and assigning it to a regexp.

   delete [] fPattern;
   GenPattern(str);
   return *this;
}

//______________________________________________________________________________
TRegexp& TRegexp::operator=(const TString &str)
{
   // Assignment operator taking a TString.

   delete [] fPattern;
   GenPattern(str.Data());
   return *this;
}

//______________________________________________________________________________
void TRegexp::GenPattern(const char *str)
{
   // Generate the regular expression pattern.

   fPattern = new Pattern_t[fgMaxpat];
   int error = ::Makepat(str, fPattern, fgMaxpat);
   fStat = (error < 3) ? (EStatVal) error : kToolong;
}

//______________________________________________________________________________
void TRegexp::CopyPattern(const TRegexp& r)
{
   // Copy the regular expression pattern.

   fPattern = new Pattern_t[fgMaxpat];
   memcpy(fPattern, r.fPattern, fgMaxpat * sizeof(Pattern_t));
   fStat = r.fStat;
}

//______________________________________________________________________________
const char *TRegexp::MakeWildcard(const char *re)
{
   // This routine transforms a wildcarding regular expression into
   // a general regular expression used for pattern matching.
   // When using wildcards the regular expression is assumed to be
   // preceded by a "^" (BOL) and terminated by a "$" (EOL). Also, all
   // "*"'s (closures) are assumed to be preceded by a "." (i.e. any character,
   // except "/"'s) and all .'s are escaped (so *.ps is different from *.eps).
   // The special treatment of "/" allows the easy matching of pathnames, e.g.
   // "*.root" will match "aap.root", but not "pipo/aap.root".

   static char buf[fgMaxpat];
   char *s = buf;
   int   len = strlen(re);

   if (!re || !len) return "";

   for (int i = 0; i < len; i++) {
      if (i == 0 && re[i] != '^')
         *s++ = '^';
      if (re[i] == '*') {
         //*s++ = '.';
#ifndef R__WIN32
         const char *wc = "[a-zA-Z0-9_\\.,:- ]";
#else
         const char *wc = "[a-zA-Z0-9_.,- ]";
#endif
         strcpy(s, wc);
         s += strlen(wc);
      }
      if (re[i] == '.')
         *s++ = '\\';
      *s++ = re[i];
      if (i == len-1 && re[i] != '$')
         *s++ = '$';
   }
   *s = '\0';
   return buf;
}

//______________________________________________________________________________
Ssiz_t TRegexp::Index(const TString& string, Ssiz_t* len, Ssiz_t i) const
{
   // Find the first occurance of the regexp in string and return the position.
   // Len is length of the matched string and i is the offset at which the
   // matching should start.

   if (fStat != kOK)
      Error("TRegexp::Index", "Bad Regular Expression");

   const char* startp;
   const char* s = string.Data();
   Ssiz_t slen = string.Length();
   if (slen < i) return kNPOS;
   const char* endp = ::Matchs(s+i, slen-i, fPattern, &startp);
   if (endp) {
      *len = endp - startp;
      return startp - s;
   } else {
      *len = 0;
      return kNPOS;
   }
}

//______________________________________________________________________________
TRegexp::EStatVal TRegexp::Status()
{
   // Check status of regexp.

   EStatVal temp = fStat;
   fStat = kOK;
   return temp;
}

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TString member functions, put here so the linker will include        //
// them only if regular expressions are used.                           //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
Ssiz_t TString::Index(const TRegexp& r, Ssiz_t start) const
{
   // Find the first occurance of the regexp in string and return the position.
   // Start is the offset at which the search should start.

   Ssiz_t len;
   return r.Index(*this, &len, start); // len not used
}

//______________________________________________________________________________
Ssiz_t TString::Index(const TRegexp& r, Ssiz_t* extent, Ssiz_t start) const
{
   // Find the first occurance of the regexp in string and return the position.
   // Extent is length of the matched string and start is the offset at which
   // the matching should start.

   return r.Index(*this, extent, start);
}

//______________________________________________________________________________
TSubString TString::operator()(const TRegexp& r, Ssiz_t start)
{
   // Return the substring found by applying the regexp starting at start.

   Ssiz_t len;
   Ssiz_t begin = Index(r, &len, start);
   return TSubString(*this, begin, len);
}

//______________________________________________________________________________
TSubString TString::operator()(const TRegexp& r)
{
   // Return the substring found by applying the regexp.

   return (*this)(r,0);
}

//______________________________________________________________________________
TSubString TString::operator()(const TRegexp& r, Ssiz_t start) const
{
   // Return the substring found by applying the regexp starting at start.

   Ssiz_t len;
   Ssiz_t begin = Index(r, &len, start);
   return TSubString(*this, begin, len);
}

//______________________________________________________________________________
TSubString TString::operator()(const TRegexp& r) const
{
   // Return the substring found by applying the regexp.

   return (*this)(r,0);
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/dom/shadow/InsertionPoint.h"

#include "core/HTMLNames.h"
#include "core/dom/Document.h"
#include "core/dom/ElementTraversal.h"
#include "core/dom/QualifiedName.h"
#include "core/dom/StaticNodeList.h"
#include "core/dom/shadow/ElementShadow.h"

namespace blink {

using namespace HTMLNames;

InsertionPoint::InsertionPoint(const QualifiedName& tagName, Document& document)
    : HTMLElement(tagName, document, CreateInsertionPoint)
    , m_registeredWithShadowRoot(false)
{
    setHasCustomStyleCallbacks();
}

InsertionPoint::~InsertionPoint()
{
}

void InsertionPoint::setDistribution(ContentDistribution& distribution)
{
    if (shouldUseFallbackElements()) {
        for (Node* child = firstChild(); child; child = child->nextSibling())
            child->lazyReattachIfAttached();
    }

    // Attempt not to reattach nodes that would be distributed to the exact same
    // location by comparing the old and new distributions.

    size_t i = 0;
    size_t j = 0;

    for ( ; i < m_distribution.size() && j < distribution.size(); ++i, ++j) {
        if (m_distribution.size() < distribution.size()) {
            // If the new distribution is larger than the old one, reattach all nodes in
            // the new distribution that were inserted.
            for ( ; j < distribution.size() && m_distribution.at(i) != distribution.at(j); ++j)
                distribution.at(j)->lazyReattachIfAttached();
        } else if (m_distribution.size() > distribution.size()) {
            // If the old distribution is larger than the new one, reattach all nodes in
            // the old distribution that were removed.
            for ( ; i < m_distribution.size() && m_distribution.at(i) != distribution.at(j); ++i)
                m_distribution.at(i)->lazyReattachIfAttached();
        } else if (m_distribution.at(i) != distribution.at(j)) {
            // If both distributions are the same length reattach both old and new.
            m_distribution.at(i)->lazyReattachIfAttached();
            distribution.at(j)->lazyReattachIfAttached();
        }
    }

    // If we hit the end of either list above we need to reattach all remaining nodes.

    for ( ; i < m_distribution.size(); ++i)
        m_distribution.at(i)->lazyReattachIfAttached();

    for ( ; j < distribution.size(); ++j)
        distribution.at(j)->lazyReattachIfAttached();

    m_distribution.swap(distribution);
    m_distribution.shrinkToFit();
}

void InsertionPoint::attach(const AttachContext& context)
{
    // We need to attach the distribution here so that they're inserted in the right order
    // otherwise the n^2 protection inside RenderTreeBuilder will cause them to be
    // inserted in the wrong place later. This also lets distributed nodes benefit from
    // the n^2 protection.
    for (size_t i = 0; i < m_distribution.size(); ++i) {
        if (m_distribution.at(i)->needsAttach())
            m_distribution.at(i)->attach(context);
    }

    HTMLElement::attach(context);
}

void InsertionPoint::detach(const AttachContext& context)
{
    for (size_t i = 0; i < m_distribution.size(); ++i)
        m_distribution.at(i)->lazyReattachIfAttached();

    HTMLElement::detach(context);
}

void InsertionPoint::willRecalcStyle(StyleRecalcChange change)
{
    if (change < Inherit && styleChangeType() < SubtreeStyleChange)
        return;
    for (size_t i = 0; i < m_distribution.size(); ++i)
        m_distribution.at(i)->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::PropagateInheritChangeToDistributedNodes));
}

bool InsertionPoint::shouldUseFallbackElements() const
{
    return isActive() && !hasDistribution();
}

bool InsertionPoint::canBeActive() const
{
    if (!isInShadowTree())
        return false;
    return !Traversal<InsertionPoint>::firstAncestor(*this);
}

bool InsertionPoint::isActive() const
{
    if (!canBeActive())
        return false;
    ShadowRoot* shadowRoot = containingShadowRoot();
    if (!shadowRoot)
        return false;
    if (!isHTMLShadowElement(*this) || shadowRoot->descendantShadowElementCount() <= 1)
        return true;

    // Slow path only when there are more than one shadow elements in a shadow tree. That should be a rare case.
    const WillBeHeapVector<RefPtrWillBeMember<InsertionPoint> >& insertionPoints = shadowRoot->descendantInsertionPoints();
    for (size_t i = 0; i < insertionPoints.size(); ++i) {
        InsertionPoint* point = insertionPoints[i].get();
        if (isHTMLShadowElement(*point))
            return point == this;
    }
    return true;
}

bool InsertionPoint::isShadowInsertionPoint() const
{
    return isHTMLShadowElement(*this) && isActive();
}

bool InsertionPoint::isContentInsertionPoint() const
{
    return isHTMLContentElement(*this) && isActive();
}

PassRefPtrWillBeRawPtr<StaticNodeList> InsertionPoint::getDistributedNodes()
{
    document().updateDistributionForNodeIfNeeded(this);

    WillBeHeapVector<RefPtrWillBeMember<Node> > nodes;
    nodes.reserveInitialCapacity(m_distribution.size());
    for (size_t i = 0; i < m_distribution.size(); ++i)
        nodes.uncheckedAppend(m_distribution.at(i));

    return StaticNodeList::adopt(nodes);
}

bool InsertionPoint::rendererIsNeeded(const RenderStyle& style)
{
    return !isActive() && HTMLElement::rendererIsNeeded(style);
}

void InsertionPoint::childrenChanged(const ChildrenChange& change)
{
    HTMLElement::childrenChanged(change);
    if (ShadowRoot* root = containingShadowRoot()) {
        if (ElementShadow* rootOwner = root->owner())
            rootOwner->setNeedsDistributionRecalc();
    }
}

Node::InsertionNotificationRequest InsertionPoint::insertedInto(ContainerNode* insertionPoint)
{
    HTMLElement::insertedInto(insertionPoint);
    if (ShadowRoot* root = containingShadowRoot()) {
        if (ElementShadow* rootOwner = root->owner()) {
            rootOwner->setNeedsDistributionRecalc();
            if (canBeActive() && !m_registeredWithShadowRoot && insertionPoint->treeScope().rootNode() == root) {
                m_registeredWithShadowRoot = true;
                root->didAddInsertionPoint(this);
                if (canAffectSelector())
                    rootOwner->willAffectSelector();
            }
        }
    }

    return InsertionDone;
}

void InsertionPoint::removedFrom(ContainerNode* insertionPoint)
{
    ShadowRoot* root = containingShadowRoot();
    if (!root)
        root = insertionPoint->containingShadowRoot();

    if (root) {
        if (ElementShadow* rootOwner = root->owner())
            rootOwner->setNeedsDistributionRecalc();
    }

    // host can be null when removedFrom() is called from ElementShadow destructor.
    ElementShadow* rootOwner = root ? root->owner() : 0;

    // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up.
    clearDistribution();

    if (m_registeredWithShadowRoot && insertionPoint->treeScope().rootNode() == root) {
        ASSERT(root);
        m_registeredWithShadowRoot = false;
        root->didRemoveInsertionPoint(this);
        if (rootOwner) {
            if (canAffectSelector())
                rootOwner->willAffectSelector();
        }
    }

    HTMLElement::removedFrom(insertionPoint);
}

void InsertionPoint::trace(Visitor* visitor)
{
    visitor->trace(m_distribution);
    HTMLElement::trace(visitor);
}

const InsertionPoint* resolveReprojection(const Node* projectedNode)
{
    ASSERT(projectedNode);
    const InsertionPoint* insertionPoint = 0;
    const Node* current = projectedNode;
    ElementShadow* lastElementShadow = 0;
    while (true) {
        ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*current);
        if (!shadow || shadow == lastElementShadow)
            break;
        lastElementShadow = shadow;
        const InsertionPoint* insertedTo = shadow->finalDestinationInsertionPointFor(projectedNode);
        if (!insertedTo)
            break;
        ASSERT(current != insertedTo);
        current = insertedTo;
        insertionPoint = insertedTo;
    }
    return insertionPoint;
}

void collectDestinationInsertionPoints(const Node& node, WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8>& results)
{
    const Node* current = &node;
    ElementShadow* lastElementShadow = 0;
    while (true) {
        ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*current);
        if (!shadow || shadow == lastElementShadow)
            return;
        lastElementShadow = shadow;
        const DestinationInsertionPoints* insertionPoints = shadow->destinationInsertionPointsFor(&node);
        if (!insertionPoints)
            return;
        for (size_t i = 0; i < insertionPoints->size(); ++i)
            results.append(insertionPoints->at(i).get());
        ASSERT(current != insertionPoints->last().get());
        current = insertionPoints->last().get();
    }
}

} // namespace blink
<commit_msg>Oilpan: Shadow DOM: Explicitly clear ContentDistribution objects in DistributionPool::distributeTo.<commit_after>/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/dom/shadow/InsertionPoint.h"

#include "core/HTMLNames.h"
#include "core/dom/Document.h"
#include "core/dom/ElementTraversal.h"
#include "core/dom/QualifiedName.h"
#include "core/dom/StaticNodeList.h"
#include "core/dom/shadow/ElementShadow.h"

namespace blink {

using namespace HTMLNames;

InsertionPoint::InsertionPoint(const QualifiedName& tagName, Document& document)
    : HTMLElement(tagName, document, CreateInsertionPoint)
    , m_registeredWithShadowRoot(false)
{
    setHasCustomStyleCallbacks();
}

InsertionPoint::~InsertionPoint()
{
}

void InsertionPoint::setDistribution(ContentDistribution& distribution)
{
    if (shouldUseFallbackElements()) {
        for (Node* child = firstChild(); child; child = child->nextSibling())
            child->lazyReattachIfAttached();
    }

    // Attempt not to reattach nodes that would be distributed to the exact same
    // location by comparing the old and new distributions.

    size_t i = 0;
    size_t j = 0;

    for ( ; i < m_distribution.size() && j < distribution.size(); ++i, ++j) {
        if (m_distribution.size() < distribution.size()) {
            // If the new distribution is larger than the old one, reattach all nodes in
            // the new distribution that were inserted.
            for ( ; j < distribution.size() && m_distribution.at(i) != distribution.at(j); ++j)
                distribution.at(j)->lazyReattachIfAttached();
        } else if (m_distribution.size() > distribution.size()) {
            // If the old distribution is larger than the new one, reattach all nodes in
            // the old distribution that were removed.
            for ( ; i < m_distribution.size() && m_distribution.at(i) != distribution.at(j); ++i)
                m_distribution.at(i)->lazyReattachIfAttached();
        } else if (m_distribution.at(i) != distribution.at(j)) {
            // If both distributions are the same length reattach both old and new.
            m_distribution.at(i)->lazyReattachIfAttached();
            distribution.at(j)->lazyReattachIfAttached();
        }
    }

    // If we hit the end of either list above we need to reattach all remaining nodes.

    for ( ; i < m_distribution.size(); ++i)
        m_distribution.at(i)->lazyReattachIfAttached();

    for ( ; j < distribution.size(); ++j)
        distribution.at(j)->lazyReattachIfAttached();

    m_distribution.swap(distribution);
#if ENABLE(OILPAN)
    // Deallocate a Vector and a HashMap explicitly in order that Oilpan can
    // recycle them without GC.
    distribution.clear();
#endif
    m_distribution.shrinkToFit();
}

void InsertionPoint::attach(const AttachContext& context)
{
    // We need to attach the distribution here so that they're inserted in the right order
    // otherwise the n^2 protection inside RenderTreeBuilder will cause them to be
    // inserted in the wrong place later. This also lets distributed nodes benefit from
    // the n^2 protection.
    for (size_t i = 0; i < m_distribution.size(); ++i) {
        if (m_distribution.at(i)->needsAttach())
            m_distribution.at(i)->attach(context);
    }

    HTMLElement::attach(context);
}

void InsertionPoint::detach(const AttachContext& context)
{
    for (size_t i = 0; i < m_distribution.size(); ++i)
        m_distribution.at(i)->lazyReattachIfAttached();

    HTMLElement::detach(context);
}

void InsertionPoint::willRecalcStyle(StyleRecalcChange change)
{
    if (change < Inherit && styleChangeType() < SubtreeStyleChange)
        return;
    for (size_t i = 0; i < m_distribution.size(); ++i)
        m_distribution.at(i)->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::PropagateInheritChangeToDistributedNodes));
}

bool InsertionPoint::shouldUseFallbackElements() const
{
    return isActive() && !hasDistribution();
}

bool InsertionPoint::canBeActive() const
{
    if (!isInShadowTree())
        return false;
    return !Traversal<InsertionPoint>::firstAncestor(*this);
}

bool InsertionPoint::isActive() const
{
    if (!canBeActive())
        return false;
    ShadowRoot* shadowRoot = containingShadowRoot();
    if (!shadowRoot)
        return false;
    if (!isHTMLShadowElement(*this) || shadowRoot->descendantShadowElementCount() <= 1)
        return true;

    // Slow path only when there are more than one shadow elements in a shadow tree. That should be a rare case.
    const WillBeHeapVector<RefPtrWillBeMember<InsertionPoint> >& insertionPoints = shadowRoot->descendantInsertionPoints();
    for (size_t i = 0; i < insertionPoints.size(); ++i) {
        InsertionPoint* point = insertionPoints[i].get();
        if (isHTMLShadowElement(*point))
            return point == this;
    }
    return true;
}

bool InsertionPoint::isShadowInsertionPoint() const
{
    return isHTMLShadowElement(*this) && isActive();
}

bool InsertionPoint::isContentInsertionPoint() const
{
    return isHTMLContentElement(*this) && isActive();
}

PassRefPtrWillBeRawPtr<StaticNodeList> InsertionPoint::getDistributedNodes()
{
    document().updateDistributionForNodeIfNeeded(this);

    WillBeHeapVector<RefPtrWillBeMember<Node> > nodes;
    nodes.reserveInitialCapacity(m_distribution.size());
    for (size_t i = 0; i < m_distribution.size(); ++i)
        nodes.uncheckedAppend(m_distribution.at(i));

    return StaticNodeList::adopt(nodes);
}

bool InsertionPoint::rendererIsNeeded(const RenderStyle& style)
{
    return !isActive() && HTMLElement::rendererIsNeeded(style);
}

void InsertionPoint::childrenChanged(const ChildrenChange& change)
{
    HTMLElement::childrenChanged(change);
    if (ShadowRoot* root = containingShadowRoot()) {
        if (ElementShadow* rootOwner = root->owner())
            rootOwner->setNeedsDistributionRecalc();
    }
}

Node::InsertionNotificationRequest InsertionPoint::insertedInto(ContainerNode* insertionPoint)
{
    HTMLElement::insertedInto(insertionPoint);
    if (ShadowRoot* root = containingShadowRoot()) {
        if (ElementShadow* rootOwner = root->owner()) {
            rootOwner->setNeedsDistributionRecalc();
            if (canBeActive() && !m_registeredWithShadowRoot && insertionPoint->treeScope().rootNode() == root) {
                m_registeredWithShadowRoot = true;
                root->didAddInsertionPoint(this);
                if (canAffectSelector())
                    rootOwner->willAffectSelector();
            }
        }
    }

    return InsertionDone;
}

void InsertionPoint::removedFrom(ContainerNode* insertionPoint)
{
    ShadowRoot* root = containingShadowRoot();
    if (!root)
        root = insertionPoint->containingShadowRoot();

    if (root) {
        if (ElementShadow* rootOwner = root->owner())
            rootOwner->setNeedsDistributionRecalc();
    }

    // host can be null when removedFrom() is called from ElementShadow destructor.
    ElementShadow* rootOwner = root ? root->owner() : 0;

    // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up.
    clearDistribution();

    if (m_registeredWithShadowRoot && insertionPoint->treeScope().rootNode() == root) {
        ASSERT(root);
        m_registeredWithShadowRoot = false;
        root->didRemoveInsertionPoint(this);
        if (rootOwner) {
            if (canAffectSelector())
                rootOwner->willAffectSelector();
        }
    }

    HTMLElement::removedFrom(insertionPoint);
}

void InsertionPoint::trace(Visitor* visitor)
{
    visitor->trace(m_distribution);
    HTMLElement::trace(visitor);
}

const InsertionPoint* resolveReprojection(const Node* projectedNode)
{
    ASSERT(projectedNode);
    const InsertionPoint* insertionPoint = 0;
    const Node* current = projectedNode;
    ElementShadow* lastElementShadow = 0;
    while (true) {
        ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*current);
        if (!shadow || shadow == lastElementShadow)
            break;
        lastElementShadow = shadow;
        const InsertionPoint* insertedTo = shadow->finalDestinationInsertionPointFor(projectedNode);
        if (!insertedTo)
            break;
        ASSERT(current != insertedTo);
        current = insertedTo;
        insertionPoint = insertedTo;
    }
    return insertionPoint;
}

void collectDestinationInsertionPoints(const Node& node, WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8>& results)
{
    const Node* current = &node;
    ElementShadow* lastElementShadow = 0;
    while (true) {
        ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*current);
        if (!shadow || shadow == lastElementShadow)
            return;
        lastElementShadow = shadow;
        const DestinationInsertionPoints* insertionPoints = shadow->destinationInsertionPointsFor(&node);
        if (!insertionPoints)
            return;
        for (size_t i = 0; i < insertionPoints->size(); ++i)
            results.append(insertionPoints->at(i).get());
        ASSERT(current != insertionPoints->last().get());
        current = insertionPoints->last().get();
    }
}

} // namespace blink
<|endoftext|>