<commit_before>/*
* The MIT License(MIT)
*
* Copyright(c) 2016 Victor DENIS (victordenis01@gmail.com)
*
* 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 "window.h"

namespace Fd {
	namespace Graphics {

		Window::Window(const char * title, int width, int height) :
			m_title(title),
			m_width(width),
			m_height(height)
		{
			if (!glfwInit()) {
				glfwTerminate();
				std::cout << "Failed to init GLFW" << std::endl;
				return;
			}

			m_window = glfwCreateWindow(m_width, m_height, m_title, nullptr, nullptr);
			if (!m_window) {
				glfwTerminate();
				std::cout << "Failed to create the Window" << std::endl;
				return;
			}

			glfwMakeContextCurrent(m_window);
			glfwSetWindowUserPointer(m_window, this);
			glfwSetFramebufferSizeCallback(m_window, window_resize);
			glfwSetKeyCallback(m_window, key_callback);
			glfwSetMouseButtonCallback(m_window, mouseButton_callback);
			glfwSetCursorPosCallback(m_window, cursorPosition_callback);
			glfwSwapInterval(0.0);

			if (glewInit() != GLEW_OK) {
				glfwTerminate();
				std::cout << "Failed to init GLEW" << std::endl;
				return;
			}

			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

			std::cout << "**********Feld[2D]Engine**********" << std::endl;
			std::cout << "OpenGL " << glGetString(GL_VERSION) << std::endl;
			std::cout << "**********************************" << std::endl;
			std::cout << std::endl;

			for (int i{ 0 }; i < MAX_KEYS; i++) {
				m_keys[i] = false;
				m_keyState[i] = false;
				m_keyTyped[i] = false;
			}

			for (int i{ 0 }; i < MAX_BUTTONS; i++) {
				m_mouseButtons[i] = false;
				m_mouseState[i] = false;
				m_mouseClicked[i] = false;
			}

		}

		Window::~Window()
		{
			glfwTerminate();
		}

		void Window::clear() const
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		}

		void Window::update()
		{
			for (int i{ 0 }; i < MAX_KEYS; ++i)
				m_keyTyped[i] = m_keys[i] && !m_keyState[i];

			for (int i{ 0 }; i < MAX_KEYS; ++i) {
				m_keyState[i] = m_keys[i];
			}

			for (int i{ 0 }; i < MAX_BUTTONS; ++i)
				m_mouseClicked[i] = m_mouseButtons[i] && !m_mouseState[i];

			for (int i{ 0 }; i < MAX_BUTTONS; ++i) {
				m_mouseState[i] = m_mouseButtons[i];
			}

			GLenum error = glGetError();

			if (error != GL_NO_ERROR)
				std::cout << "OpenGL error: " << error << std::endl;

			glfwSwapBuffers(m_window);
			glfwPollEvents();
		}

		bool Window::closed() const
		{
			return glfwWindowShouldClose(m_window) == 1;
		}

		bool Window::isKeyPressed(unsigned keyCode) const
		{
			if (keyCode >= MAX_KEYS)
				return false;

			return m_keys[keyCode];
		}

		bool Window::isKeyTyped(unsigned keyCode) const
		{
			if (keyCode >= MAX_KEYS)
				return false;

			return m_keyTyped[keyCode];
		}

		bool Window::isMouseButtonPressed(unsigned button) const
		{
			if (button >= MAX_BUTTONS)
				return false;

			return m_mouseButtons[button];
		}

		bool Window::isMouseButtonClicked(unsigned button) const
		{
			if (button >= MAX_BUTTONS)
				return false;

			return m_mouseClicked[button];
		}

		void Window::getMousePosition(double & x, double & y) const
		{
			x = mx;
			y = my;
		}

		void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
		{
			Window *win = static_cast<Window*>(glfwGetWindowUserPointer(window));
			win->m_keys[key] = action != GLFW_RELEASE;
		}

		void mouseButton_callback(GLFWwindow * window, int button, int action, int mods)
		{
			Window *win = static_cast<Window*>(glfwGetWindowUserPointer(window));
			win->m_mouseButtons[button] = action != GLFW_RELEASE;
		}

		void cursorPosition_callback(GLFWwindow * window, double xpos, double ypos)
		{
			Window *win = static_cast<Window*>(glfwGetWindowUserPointer(window));
			win->mx = xpos;
			win->my = ypos;
		}

		void window_resize(GLFWwindow *window, int width, int height)
		{
			glViewport(0, 0, width, height);
			Window *win = static_cast<Window*>(glfwGetWindowUserPointer(window));
			win->m_width = width;
			win->m_height = height;
		}
	}
}<commit_msg>Correct the title form in consol<commit_after>/*
* The MIT License(MIT)
*
* Copyright(c) 2016 Victor DENIS (victordenis01@gmail.com)
*
* 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 "window.h"

namespace Fd {
	namespace Graphics {

		Window::Window(const char * title, int width, int height) :
			m_title(title),
			m_width(width),
			m_height(height)
		{
			if (!glfwInit()) {
				glfwTerminate();
				std::cout << "Failed to init GLFW" << std::endl;
				return;
			}

			m_window = glfwCreateWindow(m_width, m_height, m_title, nullptr, nullptr);
			if (!m_window) {
				glfwTerminate();
				std::cout << "Failed to create the Window" << std::endl;
				return;
			}

			glfwMakeContextCurrent(m_window);
			glfwSetWindowUserPointer(m_window, this);
			glfwSetFramebufferSizeCallback(m_window, window_resize);
			glfwSetKeyCallback(m_window, key_callback);
			glfwSetMouseButtonCallback(m_window, mouseButton_callback);
			glfwSetCursorPosCallback(m_window, cursorPosition_callback);
			glfwSwapInterval(0.0);

			if (glewInit() != GLEW_OK) {
				glfwTerminate();
				std::cout << "Failed to init GLEW" << std::endl;
				return;
			}

			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

			std::cout << "************FeldEngine************" << std::endl;
			std::cout << "OpenGL " << glGetString(GL_VERSION) << std::endl;
			std::cout << "**********************************" << std::endl;
			std::cout << std::endl;

			for (int i{ 0 }; i < MAX_KEYS; i++) {
				m_keys[i] = false;
				m_keyState[i] = false;
				m_keyTyped[i] = false;
			}

			for (int i{ 0 }; i < MAX_BUTTONS; i++) {
				m_mouseButtons[i] = false;
				m_mouseState[i] = false;
				m_mouseClicked[i] = false;
			}

		}

		Window::~Window()
		{
			glfwTerminate();
		}

		void Window::clear() const
		{
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		}

		void Window::update()
		{
			for (int i{ 0 }; i < MAX_KEYS; ++i)
				m_keyTyped[i] = m_keys[i] && !m_keyState[i];

			for (int i{ 0 }; i < MAX_KEYS; ++i) {
				m_keyState[i] = m_keys[i];
			}

			for (int i{ 0 }; i < MAX_BUTTONS; ++i)
				m_mouseClicked[i] = m_mouseButtons[i] && !m_mouseState[i];

			for (int i{ 0 }; i < MAX_BUTTONS; ++i) {
				m_mouseState[i] = m_mouseButtons[i];
			}

			GLenum error = glGetError();

			if (error != GL_NO_ERROR)
				std::cout << "OpenGL error: " << error << std::endl;

			glfwSwapBuffers(m_window);
			glfwPollEvents();
		}

		bool Window::closed() const
		{
			return glfwWindowShouldClose(m_window) == 1;
		}

		bool Window::isKeyPressed(unsigned keyCode) const
		{
			if (keyCode >= MAX_KEYS)
				return false;

			return m_keys[keyCode];
		}

		bool Window::isKeyTyped(unsigned keyCode) const
		{
			if (keyCode >= MAX_KEYS)
				return false;

			return m_keyTyped[keyCode];
		}

		bool Window::isMouseButtonPressed(unsigned button) const
		{
			if (button >= MAX_BUTTONS)
				return false;

			return m_mouseButtons[button];
		}

		bool Window::isMouseButtonClicked(unsigned button) const
		{
			if (button >= MAX_BUTTONS)
				return false;

			return m_mouseClicked[button];
		}

		void Window::getMousePosition(double & x, double & y) const
		{
			x = mx;
			y = my;
		}

		void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
		{
			Window *win = static_cast<Window*>(glfwGetWindowUserPointer(window));
			win->m_keys[key] = action != GLFW_RELEASE;
		}

		void mouseButton_callback(GLFWwindow * window, int button, int action, int mods)
		{
			Window *win = static_cast<Window*>(glfwGetWindowUserPointer(window));
			win->m_mouseButtons[button] = action != GLFW_RELEASE;
		}

		void cursorPosition_callback(GLFWwindow * window, double xpos, double ypos)
		{
			Window *win = static_cast<Window*>(glfwGetWindowUserPointer(window));
			win->mx = xpos;
			win->my = ypos;
		}

		void window_resize(GLFWwindow *window, int width, int height)
		{
			glViewport(0, 0, width, height);
			Window *win = static_cast<Window*>(glfwGetWindowUserPointer(window));
			win->m_width = width;
			win->m_height = height;
		}
	}
}<|endoftext|>


<commit_before>/*

  This program will add histograms from a list of root files and write them
  to a target root file. The target file is newly created and must not be
  identical to one of the source files.

  Syntax:

       hadd targetfile source1 source2 ...
    or
       hadd -f targetfile source1 source2 ...
         (targetfile is overwritten if it exists)

  When -the -f option is specified, one can also specify the compression
  level of the target file. By default the compression level is 1, but
  if "-f0" is specified, the target file will not be compressed.
  if "-f6" is specified, the compression level 6 will be used.

  For example assume 3 files f1, f2, f3 containing histograms hn and Trees Tn
    f1 with h1 h2 h3 T1
    f2 with h1 h4 T1 T2
    f3 with h5
   the result of
     hadd -f x.root f1.root f2.root f3.root
   will be a file x.root with
     x with h1 h2 h3 h4 h5 T1 T2
   where h1 will be the sum of the 2 histograms in f1 and f2
         T1 will be the merge of the Trees in f1 and f2

   The files may contain sub-directories.

  if the source files contains histograms and Trees, one can skip
  the Trees with
       hadd -T targetfile source1 source2 ...

  Authors: Rene Brun, Dirk Geppert, Sven A. Schmidt, sven.schmidt@cern.ch
         : rewritten from scratch by Rene Brun (30 November 2005)
            to support files with nested directories.
 */

#include "RConfig.h"
#include <string>
#include "TChain.h"
#include "TFile.h"
#include "TH1.h"
#include "TKey.h"
#include "TObjString.h"
#include "Riostream.h"

TList *FileList;
TFile *Target, *Source;
Bool_t noTrees;

void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir );

int main( int argc, char **argv ) {

  if ( argc < 4 || "-h" == string(argv[1]) || "--help" == string(argv[1]) ) {
    cout << "Usage: " << argv[0] << " [-f] [-T] targetfile source1 source2 [source3 ...]" << endl;
    cout << "This program will add histograms from a list of root files and write them" << endl;
    cout << "to a target root file. The target file is newly created and must not " << endl;
    cout << "exist, or if -f (\"force\") is given, must not be one of the source files." << endl;
    cout << "Supply at least two source files for this to make sense... ;-)" << endl;
    cout << "If the first argument is -T, Trees are not merged" <<endl;
    cout << "When -the -f option is specified, one can also specify the compression" <<endl;
    cout << "level of the target file. By default the compression level is 1, but" <<endl;
    cout << "if \"-f0\" is specified, the target file will not be compressed." <<endl;
    cout << "if \"-f6\" is specified, the compression level 6 will be used." <<endl;
    return 1;
  }
  FileList = new TList();

  Bool_t force = (!strcmp(argv[1],"-f") || !strcmp(argv[2],"-f"));
  noTrees = (!strcmp(argv[1],"-T") || !strcmp(argv[2],"-T"));
  Int_t newcomp = 1;
  char ft[4];
  for (int j=0;j<9;j++) {
     sprintf(ft,"-f%d",j);
     if (!strcmp(argv[1],ft) || !strcmp(argv[2],ft)) {
        force = kTRUE;
         newcomp = j;
        break;
     }
  }

  int ffirst = 2;
  if (force) ffirst++;
  if (noTrees) ffirst++;

  cout << "Target file: " << argv[ffirst-1] << endl;
  Target = TFile::Open( argv[ffirst-1], (force?"RECREATE":"CREATE") );
  if (!Target || Target->IsZombie()) {
     cerr << "Error opening target file (does " << argv[ffirst-1] << " exist?)." << endl;
     cerr << "Pass \"-f\" argument to force re-creation of output file." << endl;
     exit(1);
  }
  Target->SetCompressionLevel(newcomp);

  // by default hadd can merge Trees in a file that can go up to 100 Gbytes
  Long64_t maxsize = 100000000; //100GB
  maxsize *= 100;  //to bypass some compiler limitations with big constants
  TTree::SetMaxTreeSize(maxsize);

  for ( int i = ffirst; i < argc; i++ ) {
    cout << "Source file " << i-ffirst+1 << ": " << argv[i] << endl;
    Source = TFile::Open( argv[i] );
    FileList->Add(Source);
  }

  MergeRootfile( Target, FileList,0 );

 //must delete Target to avoid a problem with dictionaries in~ TROOT
  delete Target;

  return 0;
}

void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir ) {

  cout << "Target path: " << target->GetPath() << endl;
  TString path( (char*)strstr( target->GetPath(), ":" ) );
  path.Remove( 0, 2 );

  TDirectory *first_source = (TDirectory*)sourcelist->First();
  THashList allNames;
  while(first_source) {
     TDirectory *current_sourcedir = first_source->GetDirectory(path);
     if (!current_sourcedir) {
        first_source = (TDirectory*)sourcelist->After(first_source);
        continue;
     }

     // loop over all keys in this directory
     TChain *globChain = 0;
     TIter nextkey( current_sourcedir->GetListOfKeys() );
     TKey *key, *oldkey=0;
     //gain time, do not add the objects in the list in memory
     TH1::AddDirectory(kFALSE);

     while ( (key = (TKey*)nextkey())) {
        if (current_sourcedir == target) break;
       //keep only the highest cycle number for each key
       if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;
       if (allNames.FindObject(key->GetName())) continue;
       allNames.Add(new TObjString(key->GetName()));

       // read object from first source file
       current_sourcedir->cd();
       TObject *obj = key->ReadObj();

       if ( obj->IsA()->InheritsFrom( TH1::Class() ) ) {
         // descendant of TH1 -> merge it

         TH1 *h1 = (TH1*)obj;
         TList listH;

         // loop over all source files and add the content of the
         // correspondant histogram to the one pointed to by "h1"
         TFile *nextsource = (TFile*)sourcelist->After( first_source );
         while ( nextsource ) {

           // make sure we are at the correct directory level by cd'ing to path
           TDirectory *ndir = nextsource->GetDirectory(path);
           if (ndir) {
              ndir->cd();
              TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(h1->GetName());
              if (key2) {
                 listH.Add(key2->ReadObj());
                 h1->Merge(&listH);
                 listH.Delete();
              }
           }

           nextsource = (TFile*)sourcelist->After( nextsource );
         }
       }
       else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {

         // loop over all source files create a chain of Trees "globChain"
         if (!noTrees) {
            TString obj_name;
            if (path.Length()) {
               obj_name = path + "/" + obj->GetName();
            } else {
               obj_name = obj->GetName();
            }

            globChain = new TChain(obj_name);
            globChain->Add(first_source->GetName());
            TFile *nextsource = (TFile*)sourcelist->After( first_source );
            while ( nextsource ) {
               //do not add to the list a file that does not contain this Tree
               TFile *curf = TFile::Open(nextsource->GetName());
               if (curf) {
                  Bool_t mustAdd = kFALSE;
                  if (curf->FindKey(obj_name)) {
                     mustAdd = kTRUE;
                  } else {
                     //we could be more clever here. No need to import the object
                     //we are missing a function in TDirectory
                     TObject *aobj = curf->Get(obj_name);
                     if (aobj) { mustAdd = kTRUE; delete aobj;}
                  }
                  if (mustAdd) {
                    globChain->Add(nextsource->GetName());
                  }
               }
               delete curf;
               nextsource = (TFile*)sourcelist->After( nextsource );
            }
         }

       } else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
         // it's a subdirectory

         cout << "Found subdirectory " << obj->GetName() << endl;
         // create a new subdir of same name and title in the target file
         target->cd();
         TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );

         // newdir is now the starting point of another round of merging
         // newdir still knows its depth within the target file via
         // GetPath(), so we can still figure out where we are in the recursion
         MergeRootfile( newdir, sourcelist,1);

       } else {

         // object is of no type that we know or can handle
         cout << "Unknown object type, name: "
              << obj->GetName() << " title: " << obj->GetTitle() << endl;
       }

       // now write the merged histogram (which is "in" obj) to the target file
       // note that this will just store obj in the current directory level,
       // which is not persistent until the complete directory itself is stored
       // by "target->Write()" below
       if ( obj ) {
          target->cd();

          //!!if the object is a tree, it is stored in globChain...
          if(obj->IsA()->InheritsFrom( "TDirectory" )) {
             //printf("cas d'une directory\n");
          } else if(obj->IsA()->InheritsFrom( "TTree" )) {
             if (!noTrees) {
                globChain->ls();
                //globChain->Merge(target->GetFile(),0,"keep fast");
                globChain->Merge(target->GetFile(),0,"keep");
                delete globChain;
             }
          } else {
             obj->Write( key->GetName() );
          }
       }
       oldkey = key;

     } // while ( ( TKey *key = (TKey*)nextkey() ) )
     first_source = (TDirectory*)sourcelist->After(first_source);
  }
  // save modifications to target file
  target->SaveSelf(kTRUE);
  if (!isdir) sourcelist->Remove(sourcelist->First());
}
<commit_msg>Re-enable the use of the fast merging after we fixed the issue with TTree with TClonesArrays<commit_after>/*

  This program will add histograms from a list of root files and write them
  to a target root file. The target file is newly created and must not be
  identical to one of the source files.

  Syntax:

       hadd targetfile source1 source2 ...
    or
       hadd -f targetfile source1 source2 ...
         (targetfile is overwritten if it exists)

  When -the -f option is specified, one can also specify the compression
  level of the target file. By default the compression level is 1, but
  if "-f0" is specified, the target file will not be compressed.
  if "-f6" is specified, the compression level 6 will be used.

  For example assume 3 files f1, f2, f3 containing histograms hn and Trees Tn
    f1 with h1 h2 h3 T1
    f2 with h1 h4 T1 T2
    f3 with h5
   the result of
     hadd -f x.root f1.root f2.root f3.root
   will be a file x.root with
     x with h1 h2 h3 h4 h5 T1 T2
   where h1 will be the sum of the 2 histograms in f1 and f2
         T1 will be the merge of the Trees in f1 and f2

   The files may contain sub-directories.

  if the source files contains histograms and Trees, one can skip
  the Trees with
       hadd -T targetfile source1 source2 ...

  Authors: Rene Brun, Dirk Geppert, Sven A. Schmidt, sven.schmidt@cern.ch
         : rewritten from scratch by Rene Brun (30 November 2005)
            to support files with nested directories.
 */

#include "RConfig.h"
#include <string>
#include "TChain.h"
#include "TFile.h"
#include "TH1.h"
#include "TKey.h"
#include "TObjString.h"
#include "Riostream.h"

TList *FileList;
TFile *Target, *Source;
Bool_t noTrees;

void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir );

int main( int argc, char **argv ) {

  if ( argc < 4 || "-h" == string(argv[1]) || "--help" == string(argv[1]) ) {
    cout << "Usage: " << argv[0] << " [-f] [-T] targetfile source1 source2 [source3 ...]" << endl;
    cout << "This program will add histograms from a list of root files and write them" << endl;
    cout << "to a target root file. The target file is newly created and must not " << endl;
    cout << "exist, or if -f (\"force\") is given, must not be one of the source files." << endl;
    cout << "Supply at least two source files for this to make sense... ;-)" << endl;
    cout << "If the first argument is -T, Trees are not merged" <<endl;
    cout << "When -the -f option is specified, one can also specify the compression" <<endl;
    cout << "level of the target file. By default the compression level is 1, but" <<endl;
    cout << "if \"-f0\" is specified, the target file will not be compressed." <<endl;
    cout << "if \"-f6\" is specified, the compression level 6 will be used." <<endl;
    return 1;
  }
  FileList = new TList();

  Bool_t force = (!strcmp(argv[1],"-f") || !strcmp(argv[2],"-f"));
  noTrees = (!strcmp(argv[1],"-T") || !strcmp(argv[2],"-T"));
  Int_t newcomp = 1;
  char ft[4];
  for (int j=0;j<9;j++) {
     sprintf(ft,"-f%d",j);
     if (!strcmp(argv[1],ft) || !strcmp(argv[2],ft)) {
        force = kTRUE;
         newcomp = j;
        break;
     }
  }

  int ffirst = 2;
  if (force) ffirst++;
  if (noTrees) ffirst++;

  cout << "Target file: " << argv[ffirst-1] << endl;
  Target = TFile::Open( argv[ffirst-1], (force?"RECREATE":"CREATE") );
  if (!Target || Target->IsZombie()) {
     cerr << "Error opening target file (does " << argv[ffirst-1] << " exist?)." << endl;
     cerr << "Pass \"-f\" argument to force re-creation of output file." << endl;
     exit(1);
  }
  Target->SetCompressionLevel(newcomp);

  // by default hadd can merge Trees in a file that can go up to 100 Gbytes
  Long64_t maxsize = 100000000; //100GB
  maxsize *= 100;  //to bypass some compiler limitations with big constants
  TTree::SetMaxTreeSize(maxsize);

  for ( int i = ffirst; i < argc; i++ ) {
    cout << "Source file " << i-ffirst+1 << ": " << argv[i] << endl;
    Source = TFile::Open( argv[i] );
    FileList->Add(Source);
  }

  MergeRootfile( Target, FileList,0 );

 //must delete Target to avoid a problem with dictionaries in~ TROOT
  delete Target;

  return 0;
}

void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir ) {

  cout << "Target path: " << target->GetPath() << endl;
  TString path( (char*)strstr( target->GetPath(), ":" ) );
  path.Remove( 0, 2 );

  TDirectory *first_source = (TDirectory*)sourcelist->First();
  THashList allNames;
  while(first_source) {
     TDirectory *current_sourcedir = first_source->GetDirectory(path);
     if (!current_sourcedir) {
        first_source = (TDirectory*)sourcelist->After(first_source);
        continue;
     }

     // loop over all keys in this directory
     TChain *globChain = 0;
     TIter nextkey( current_sourcedir->GetListOfKeys() );
     TKey *key, *oldkey=0;
     //gain time, do not add the objects in the list in memory
     TH1::AddDirectory(kFALSE);

     while ( (key = (TKey*)nextkey())) {
        if (current_sourcedir == target) break;
       //keep only the highest cycle number for each key
       if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;
       if (allNames.FindObject(key->GetName())) continue;
       allNames.Add(new TObjString(key->GetName()));

       // read object from first source file
       current_sourcedir->cd();
       TObject *obj = key->ReadObj();

       if ( obj->IsA()->InheritsFrom( TH1::Class() ) ) {
         // descendant of TH1 -> merge it

         TH1 *h1 = (TH1*)obj;
         TList listH;

         // loop over all source files and add the content of the
         // correspondant histogram to the one pointed to by "h1"
         TFile *nextsource = (TFile*)sourcelist->After( first_source );
         while ( nextsource ) {

           // make sure we are at the correct directory level by cd'ing to path
           TDirectory *ndir = nextsource->GetDirectory(path);
           if (ndir) {
              ndir->cd();
              TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(h1->GetName());
              if (key2) {
                 listH.Add(key2->ReadObj());
                 h1->Merge(&listH);
                 listH.Delete();
              }
           }

           nextsource = (TFile*)sourcelist->After( nextsource );
         }
       }
       else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {

         // loop over all source files create a chain of Trees "globChain"
         if (!noTrees) {
            TString obj_name;
            if (path.Length()) {
               obj_name = path + "/" + obj->GetName();
            } else {
               obj_name = obj->GetName();
            }

            globChain = new TChain(obj_name);
            globChain->Add(first_source->GetName());
            TFile *nextsource = (TFile*)sourcelist->After( first_source );
            while ( nextsource ) {
               //do not add to the list a file that does not contain this Tree
               TFile *curf = TFile::Open(nextsource->GetName());
               if (curf) {
                  Bool_t mustAdd = kFALSE;
                  if (curf->FindKey(obj_name)) {
                     mustAdd = kTRUE;
                  } else {
                     //we could be more clever here. No need to import the object
                     //we are missing a function in TDirectory
                     TObject *aobj = curf->Get(obj_name);
                     if (aobj) { mustAdd = kTRUE; delete aobj;}
                  }
                  if (mustAdd) {
                    globChain->Add(nextsource->GetName());
                  }
               }
               delete curf;
               nextsource = (TFile*)sourcelist->After( nextsource );
            }
         }

       } else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
         // it's a subdirectory

         cout << "Found subdirectory " << obj->GetName() << endl;
         // create a new subdir of same name and title in the target file
         target->cd();
         TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );

         // newdir is now the starting point of another round of merging
         // newdir still knows its depth within the target file via
         // GetPath(), so we can still figure out where we are in the recursion
         MergeRootfile( newdir, sourcelist,1);

       } else {

         // object is of no type that we know or can handle
         cout << "Unknown object type, name: "
              << obj->GetName() << " title: " << obj->GetTitle() << endl;
       }

       // now write the merged histogram (which is "in" obj) to the target file
       // note that this will just store obj in the current directory level,
       // which is not persistent until the complete directory itself is stored
       // by "target->Write()" below
       if ( obj ) {
          target->cd();

          //!!if the object is a tree, it is stored in globChain...
          if(obj->IsA()->InheritsFrom( "TDirectory" )) {
             //printf("cas d'une directory\n");
          } else if(obj->IsA()->InheritsFrom( "TTree" )) {
             if (!noTrees) {
                globChain->ls();
                globChain->Merge(target->GetFile(),0,"keep fast");
                delete globChain;
             }
          } else {
             obj->Write( key->GetName() );
          }
       }
       oldkey = key;

     } // while ( ( TKey *key = (TKey*)nextkey() ) )
     first_source = (TDirectory*)sourcelist->After(first_source);
  }
  // save modifications to target file
  target->SaveSelf(kTRUE);
  if (!isdir) sourcelist->Remove(sourcelist->First());
}
<|endoftext|>


<commit_before>//
// Content.cpp
//
// Implements the ContentManager class, including the ability to read
// and write the contents to an XML file.
//
// Copyright (c) 2001 Virtual Terrain Project.
// Free for all uses, see license.txt for details.
//

#ifdef _MSC_VER
#pragma warning( disable : 4786 )
#endif

#include <stdio.h>
#include "xmlhelper/easyxml.hpp"
#include "Content.h"

////////////////////////////////////////////////////////////////////////
// Implementation of class vtTagArray
//

void vtTagArray::AddTag(vtTag *pTag)
{
	m_tags.Append(pTag);
}

void vtTagArray::AddTag(const char *name, const char *value)
{
	vtTag *tag = new vtTag;
	tag->name = name;
	tag->value = value;
	m_tags.Append(tag);
}

vtTag *vtTagArray::FindTag(const char *name)
{
	int size = m_tags.GetSize();
	vtTag *tag;
	for (int i = 0; i < size; i++)
	{
		tag = m_tags[i];
		if (!tag->name.CompareNoCase(name))
			return tag;
	}
	return NULL;
}

vtTag *vtTagArray::GetTag(int index)
{
	return m_tags.GetAt(index);
}

int vtTagArray::NumTags()
{
	return m_tags.GetSize();
}

void vtTagArray::RemoveTag(int index)
{
	m_tags.RemoveAt(index);
}

void vtTagArray::RemoveTag(const char *szTagName)
{
	int size = m_tags.GetSize();
	vtTag *tag;
	for (int i = 0; i < size; i++)
	{
		tag = m_tags[i];
		if (!tag->name.CompareNoCase(szTagName))
		{
			m_tags.RemoveAt(i);
			break;
		}
	}
}

void vtTagArray::SetValue(const char *name, const char *szValue)
{
	vtTag *tag = FindTag(name);
	if (tag)
		tag->value = szValue;
	else
		AddTag(name, szValue);
}

void vtTagArray::SetValue(const char *name, int iValue)
{
	vtString str;
	str.Format("%d", iValue);
	SetValue(name, str);
}

void vtTagArray::SetValue(const char *name, double dValue)
{
	vtString str;
	str.Format("%lf", dValue);
	SetValue(name, str);
}

const char *vtTagArray::GetValue(const char *name)
{
	vtTag *tag = FindTag(name);
	if (tag)
		return tag->value;
	else
		return NULL;
}

bool vtTagArray::GetValue(const char *name, vtString &string)
{
	vtTag *tag = FindTag(name);
	if (tag)
		string = tag->value;
	return (tag != NULL);
}

bool vtTagArray::GetValue(const char *name, int &value)
{
	vtTag *tag = FindTag(name);
	if (tag)
		value = atoi((const char *)tag->value);
	return (tag != NULL);
}

bool vtTagArray::GetValue(const char *name, double &value)
{
	vtTag *tag = FindTag(name);
	if (tag)
		value = atof((const char *)tag->value);
	return (tag != NULL);
}

////////////////////////////////////////////////////////////////////////
// Implementation of class vtItem
//

vtItem::~vtItem()
{
	// clean up
	Empty();
}

void vtItem::Empty()
{
	for (int i = 0; i < m_models.GetSize(); i++)
	{
		delete m_models.GetAt(i);
	}
	m_models.Empty();
}

void vtItem::RemoveModel(vtModel *model)
{
	int i = m_models.Find(model);
	m_models.RemoveAt(i);
	delete model;
}

////////////////////////////////////////////////////////////////////////
// Visitor class, for XML parsing of Content files.
////////////////////////////////////////////////////////////////////////

class ContentVisitor : public XMLVisitor
{
public:
	ContentVisitor(vtContentManager *man)
	: _level(0), _hasException(false), m_pMan(man) {}

	virtual ~ContentVisitor() {}

	void startXML();
	void endXML();
	void startElement(const char * name, const XMLAttributes &atts);
	void endElement(const char * name);
	void data(const char * s, int length);

	bool hasException() const { return _hasException; }
	xh_io_exception &getException() { return _exception; }
	void setException(const xh_io_exception &exception)
	{
		_exception = exception;
		_hasException = true;
	}

private:
	struct State
	{
		State () : item(0), type("") {}
		State (vtItem * _item, const char * _type)
			: item(_item), type(_type) {}
		vtItem * item;
		string type;
	};

	State &state () { return _state_stack[_state_stack.size() - 1]; }

	void push_state(vtItem * _item, const char * type)
	{
		if (type == 0)
			_state_stack.push_back(State(_item, "unspecified"));
		else
			_state_stack.push_back(State(_item, type));
		_level++;
		_data = "";
	}

	void pop_state()
	{
		_state_stack.pop_back();
		_level--;
	}

	string _data;
	int _level;
	vector<State> _state_stack;
	string _base;
	xh_io_exception _exception;
	bool _hasException;

	vtContentManager *m_pMan;
};

void ContentVisitor::startXML ()
{
  _level = 0;
  _state_stack.resize(0);
}

void ContentVisitor::endXML ()
{
  _level = 0;
  _state_stack.resize(0);
}

void ContentVisitor::startElement (const char * name, const XMLAttributes &atts)
{
	State &st = state();

	if (_level == 0)
	{
		if (string(name) != (string)"vtp-content") {
			string message = "Root element name is ";
			message += name;
			message += "; expected vtp-content";
			throw xh_io_exception(message, "XML Reader");
		}
		push_state(NULL, "top");
		return;
	}

	const char * attval;

	if (_level == 1)
	{
		if (string(name) == (string)"item")
		{
			vtItem *pItem = m_pMan->NewItem();
			// Get the name.
			attval = atts.getValue("name");
			if (attval != NULL) {
				pItem->m_name = attval;
			}
			push_state(pItem, "item");
		}
		else
		{
			// Unknown field, ignore.
			push_state(NULL, "dummy");
		}
		return;
	}

	if (_level == 2)
	{
		vtItem *pItem = st.item;

		if (string(name) == (string)"model")
		{
			vtModel *pModel = new vtModel();
			pModel->m_filename = atts.getValue("filename");
			attval = atts.getValue("distance");
			if (attval && *attval)
			{
				pModel->m_distance = (float)atof(attval);
			}
			else
				pModel->m_distance = 0.0f;
			pItem->AddModel(pModel);
		}
		else
			_data = "";
	}
}

void ContentVisitor::endElement(const char * name)
{
	State &st = state();

	if (string(name) == (string)"item")
	{
		if (st.item != NULL)
		{
			m_pMan->AddItem(st.item);
		}
		pop_state();
	}
	if (_level == 2)
	{
		if (string(name) != (string)"model")
		{
			// save all other tags as literal strings
			vtTag *tag = new vtTag;
			tag->name = name;
			tag->value = _data.c_str();

			vtItem *pItem = st.item;
			pItem->AddTag(tag);
		}
	}
}

void ContentVisitor::data(const char * s, int length)
{
	if (state().item != NULL)
		_data.append(string(s, length));
}

////////////////////////////////////////////////////////////////////////
// vtContentManager class implementation.
////////////////////////////////////////////////////////////////////////

vtContentManager::~vtContentManager()
{
	// clean up
	Empty();
}

void vtContentManager::Empty()
{
	for (int i = 0; i < m_items.GetSize(); i++)
	{
		delete m_items.GetAt(i);
	}
	m_items.Empty();
}

void vtContentManager::RemoveItem(vtItem *item)
{
	int i = m_items.Find(item);
	m_items.RemoveAt(i);
	delete item;
}

vtItem *vtContentManager::FindItemByName(const char *name)
{
	for (int i = 0; i < m_items.GetSize(); i++)
	{
		vtItem *pItem = m_items.GetAt(i);
		if (!pItem->m_name.CompareNoCase(name))
			return pItem;
	}
	return NULL;
}

vtItem *vtContentManager::FindItemByType(const char *type, const char *subtype)
{
	for (int i = 0; i < m_items.GetSize(); i++)
	{
		vtItem *pItem = m_items.GetAt(i);
		vtTag *tag1 = pItem->FindTag("type");
		if (tag1 && !tag1->value.CompareNoCase(type))
		{
			if (subtype)
			{
				vtTag *tag2 = pItem->FindTag("subtype");
				if (tag2 && !tag2->value.CompareNoCase(subtype))
					return pItem;
			}
			else
				return pItem;
		}
	}
	return NULL;
}

/**
 * Read content items from an XML file.
 *
 * There is no return value because if there is an error, an
 * xh_io_exception will be thrown.
 *
 * \param filename A string containing the file path.
 */
void vtContentManager::ReadXML(const char *filename)
{
	ContentVisitor visitor(this);
	readXML(filename, visitor);
	if (visitor.hasException())
		throw visitor.getException();
}

/**
 * Write content items to an XML file.
 *
 * There is no return value because if there is an error, an
 * xh_io_exception will be thrown.
 *
 * \param filename A string containing the file path.
 */
void vtContentManager::WriteXML(const char *filename)
{
	int i, j;
	FILE *fp = fopen(filename, "wb");
	if (!fp)
	{
		throw xh_io_exception("Failed to open file", xh_location(filename),
				"XML Parser");
	}

	fprintf(fp, "<?xml version=\"1.0\"?>\n\n");

	fprintf(fp, "<vtp-content file-format-version=\"1.1\">\n");
	for (i = 0; i < m_items.GetSize(); i++)
	{
		vtItem *pItem = m_items.GetAt(i);
		const char *name = pItem->m_name;
		fprintf(fp, "\t<item name=\"%s\">\n", name);
#if 0
		if (pItem->m_type != "")
		{
			const char *type = pItem->m_type;
			fprintf(fp, "\t\t<classification type=\"%s\"", type);
			if (pItem->m_subtype != "")
			{
				const char *subtype = pItem->m_subtype;
				fprintf(fp, " subtype=\"%s\"", subtype);
			}
			fprintf(fp, " />\n");
		}
		if (pItem->m_url != "")
		{
			const char *url = pItem->m_url;
			fprintf(fp, "\t\t<link utl=\"%s\" />\n", url);
		}
#endif
		for (j = 0; j < pItem->NumTags(); j++)
		{
			vtTag *tag = pItem->GetTag(j);
			fprintf(fp, "\t\t<%s>%s</%s>\n", (const char *)tag->name,
				(const char *)tag->value, (const char *)tag->name);
		}
		for (j = 0; j < pItem->NumModels(); j++)
		{
			vtModel *pMod = pItem->GetModel(j);
			const char *filename = pMod->m_filename;
			fprintf(fp, "\t\t<model filename=\"%s\"", filename);
			if (pMod->m_distance != 0.0f)
				fprintf(fp, " distance=\"%g\"", pMod->m_distance);
			fprintf(fp, " />\n");
		}
		fprintf(fp, "\t</item>\n");
	}
	fprintf(fp, "</vtp-content>\n");
	fclose(fp);
}

<commit_msg>fixed writing of scale for content files<commit_after>//
// Content.cpp
//
// Implements the ContentManager class, including the ability to read
// and write the contents to an XML file.
//
// Copyright (c) 2001 Virtual Terrain Project.
// Free for all uses, see license.txt for details.
//

#ifdef _MSC_VER
#pragma warning( disable : 4786 )
#endif

#include <stdio.h>
#include "xmlhelper/easyxml.hpp"
#include "Content.h"

////////////////////////////////////////////////////////////////////////
// Implementation of class vtTagArray
//

void vtTagArray::AddTag(vtTag *pTag)
{
	m_tags.Append(pTag);
}

void vtTagArray::AddTag(const char *name, const char *value)
{
	vtTag *tag = new vtTag;
	tag->name = name;
	tag->value = value;
	m_tags.Append(tag);
}

vtTag *vtTagArray::FindTag(const char *name)
{
	int size = m_tags.GetSize();
	vtTag *tag;
	for (int i = 0; i < size; i++)
	{
		tag = m_tags[i];
		if (!tag->name.CompareNoCase(name))
			return tag;
	}
	return NULL;
}

vtTag *vtTagArray::GetTag(int index)
{
	return m_tags.GetAt(index);
}

int vtTagArray::NumTags()
{
	return m_tags.GetSize();
}

void vtTagArray::RemoveTag(int index)
{
	m_tags.RemoveAt(index);
}

void vtTagArray::RemoveTag(const char *szTagName)
{
	int size = m_tags.GetSize();
	vtTag *tag;
	for (int i = 0; i < size; i++)
	{
		tag = m_tags[i];
		if (!tag->name.CompareNoCase(szTagName))
		{
			m_tags.RemoveAt(i);
			break;
		}
	}
}

void vtTagArray::SetValue(const char *name, const char *szValue)
{
	vtTag *tag = FindTag(name);
	if (tag)
		tag->value = szValue;
	else
		AddTag(name, szValue);
}

void vtTagArray::SetValue(const char *name, int iValue)
{
	vtString str;
	str.Format("%d", iValue);
	SetValue(name, str);
}

void vtTagArray::SetValue(const char *name, double dValue)
{
	vtString str;
	str.Format("%lf", dValue);
	SetValue(name, str);
}

const char *vtTagArray::GetValue(const char *name)
{
	vtTag *tag = FindTag(name);
	if (tag)
		return tag->value;
	else
		return NULL;
}

bool vtTagArray::GetValue(const char *name, vtString &string)
{
	vtTag *tag = FindTag(name);
	if (tag)
		string = tag->value;
	return (tag != NULL);
}

bool vtTagArray::GetValue(const char *name, int &value)
{
	vtTag *tag = FindTag(name);
	if (tag)
		value = atoi((const char *)tag->value);
	return (tag != NULL);
}

bool vtTagArray::GetValue(const char *name, double &value)
{
	vtTag *tag = FindTag(name);
	if (tag)
		value = atof((const char *)tag->value);
	return (tag != NULL);
}

////////////////////////////////////////////////////////////////////////
// Implementation of class vtItem
//

vtItem::~vtItem()
{
	// clean up
	Empty();
}

void vtItem::Empty()
{
	for (int i = 0; i < m_models.GetSize(); i++)
	{
		delete m_models.GetAt(i);
	}
	m_models.Empty();
}

void vtItem::RemoveModel(vtModel *model)
{
	int i = m_models.Find(model);
	m_models.RemoveAt(i);
	delete model;
}

////////////////////////////////////////////////////////////////////////
// Visitor class, for XML parsing of Content files.
////////////////////////////////////////////////////////////////////////

class ContentVisitor : public XMLVisitor
{
public:
	ContentVisitor(vtContentManager *man)
	: _level(0), _hasException(false), m_pMan(man) {}

	virtual ~ContentVisitor() {}

	void startXML();
	void endXML();
	void startElement(const char * name, const XMLAttributes &atts);
	void endElement(const char * name);
	void data(const char * s, int length);

	bool hasException() const { return _hasException; }
	xh_io_exception &getException() { return _exception; }
	void setException(const xh_io_exception &exception)
	{
		_exception = exception;
		_hasException = true;
	}

private:
	struct State
	{
		State () : item(0), type("") {}
		State (vtItem * _item, const char * _type)
			: item(_item), type(_type) {}
		vtItem * item;
		string type;
	};

	State &state () { return _state_stack[_state_stack.size() - 1]; }

	void push_state(vtItem * _item, const char * type)
	{
		if (type == 0)
			_state_stack.push_back(State(_item, "unspecified"));
		else
			_state_stack.push_back(State(_item, type));
		_level++;
		_data = "";
	}

	void pop_state()
	{
		_state_stack.pop_back();
		_level--;
	}

	string _data;
	int _level;
	vector<State> _state_stack;
	string _base;
	xh_io_exception _exception;
	bool _hasException;

	vtContentManager *m_pMan;
};

void ContentVisitor::startXML ()
{
  _level = 0;
  _state_stack.resize(0);
}

void ContentVisitor::endXML ()
{
  _level = 0;
  _state_stack.resize(0);
}

void ContentVisitor::startElement (const char * name, const XMLAttributes &atts)
{
	State &st = state();

	if (_level == 0)
	{
		if (string(name) != (string)"vtp-content") {
			string message = "Root element name is ";
			message += name;
			message += "; expected vtp-content";
			throw xh_io_exception(message, "XML Reader");
		}
		push_state(NULL, "top");
		return;
	}

	const char * attval;

	if (_level == 1)
	{
		if (string(name) == (string)"item")
		{
			vtItem *pItem = m_pMan->NewItem();
			// Get the name.
			attval = atts.getValue("name");
			if (attval != NULL) {
				pItem->m_name = attval;
			}
			push_state(pItem, "item");
		}
		else
		{
			// Unknown field, ignore.
			push_state(NULL, "dummy");
		}
		return;
	}

	if (_level == 2)
	{
		vtItem *pItem = st.item;

		if (string(name) == (string)"model")
		{
			vtModel *pModel = new vtModel();
			pModel->m_filename = atts.getValue("filename");
			attval = atts.getValue("distance");
			if (attval && *attval)
			{
				pModel->m_distance = (float)atof(attval);
			}
			else
				pModel->m_distance = 0.0f;
			pItem->AddModel(pModel);
		}
		else
			_data = "";
	}
}

void ContentVisitor::endElement(const char * name)
{
	State &st = state();

	if (string(name) == (string)"item")
	{
		if (st.item != NULL)
		{
			m_pMan->AddItem(st.item);
		}
		pop_state();
	}
	if (_level == 2)
	{
		if (string(name) != (string)"model")
		{
			// save all other tags as literal strings
			vtTag *tag = new vtTag;
			tag->name = name;
			tag->value = _data.c_str();

			vtItem *pItem = st.item;
			pItem->AddTag(tag);
		}
	}
}

void ContentVisitor::data(const char * s, int length)
{
	if (state().item != NULL)
		_data.append(string(s, length));
}

////////////////////////////////////////////////////////////////////////
// vtContentManager class implementation.
////////////////////////////////////////////////////////////////////////

vtContentManager::~vtContentManager()
{
	// clean up
	Empty();
}

void vtContentManager::Empty()
{
	for (int i = 0; i < m_items.GetSize(); i++)
	{
		delete m_items.GetAt(i);
	}
	m_items.Empty();
}

void vtContentManager::RemoveItem(vtItem *item)
{
	int i = m_items.Find(item);
	m_items.RemoveAt(i);
	delete item;
}

vtItem *vtContentManager::FindItemByName(const char *name)
{
	for (int i = 0; i < m_items.GetSize(); i++)
	{
		vtItem *pItem = m_items.GetAt(i);
		if (!pItem->m_name.CompareNoCase(name))
			return pItem;
	}
	return NULL;
}

vtItem *vtContentManager::FindItemByType(const char *type, const char *subtype)
{
	for (int i = 0; i < m_items.GetSize(); i++)
	{
		vtItem *pItem = m_items.GetAt(i);
		vtTag *tag1 = pItem->FindTag("type");
		if (tag1 && !tag1->value.CompareNoCase(type))
		{
			if (subtype)
			{
				vtTag *tag2 = pItem->FindTag("subtype");
				if (tag2 && !tag2->value.CompareNoCase(subtype))
					return pItem;
			}
			else
				return pItem;
		}
	}
	return NULL;
}

/**
 * Read content items from an XML file.
 *
 * There is no return value because if there is an error, an
 * xh_io_exception will be thrown.
 *
 * \param filename A string containing the file path.
 */
void vtContentManager::ReadXML(const char *filename)
{
	ContentVisitor visitor(this);
	readXML(filename, visitor);
	if (visitor.hasException())
		throw visitor.getException();
}

/**
 * Write content items to an XML file.
 *
 * There is no return value because if there is an error, an
 * xh_io_exception will be thrown.
 *
 * \param filename A string containing the file path.
 */
void vtContentManager::WriteXML(const char *filename)
{
	int i, j;
	FILE *fp = fopen(filename, "wb");
	if (!fp)
	{
		throw xh_io_exception("Failed to open file", xh_location(filename),
				"XML Parser");
	}

	fprintf(fp, "<?xml version=\"1.0\"?>\n\n");

	fprintf(fp, "<vtp-content file-format-version=\"1.1\">\n");
	for (i = 0; i < m_items.GetSize(); i++)
	{
		vtItem *pItem = m_items.GetAt(i);
		const char *name = pItem->m_name;
		fprintf(fp, "\t<item name=\"%s\">\n", name);
#if 0
		if (pItem->m_type != "")
		{
			const char *type = pItem->m_type;
			fprintf(fp, "\t\t<classification type=\"%s\"", type);
			if (pItem->m_subtype != "")
			{
				const char *subtype = pItem->m_subtype;
				fprintf(fp, " subtype=\"%s\"", subtype);
			}
			fprintf(fp, " />\n");
		}
		if (pItem->m_url != "")
		{
			const char *url = pItem->m_url;
			fprintf(fp, "\t\t<link utl=\"%s\" />\n", url);
		}
#endif
		for (j = 0; j < pItem->NumTags(); j++)
		{
			vtTag *tag = pItem->GetTag(j);
			fprintf(fp, "\t\t<%s>%s</%s>\n", (const char *)tag->name,
				(const char *)tag->value, (const char *)tag->name);
		}
		for (j = 0; j < pItem->NumModels(); j++)
		{
			vtModel *pMod = pItem->GetModel(j);
			const char *filename = pMod->m_filename;
			fprintf(fp, "\t\t<model filename=\"%s\"", filename);
			if (pMod->m_distance != 0.0f)
				fprintf(fp, " distance=\"%g\"", pMod->m_distance);
			if (pMod->m_scale != 1.0f)
				fprintf(fp, " scale=\"%g\"", pMod->m_scale);
			fprintf(fp, " />\n");
		}
		fprintf(fp, "\t</item>\n");
	}
	fprintf(fp, "</vtp-content>\n");
	fclose(fp);
}

<|endoftext|>


<commit_before>/*******************************************************************************
 * tests/core/hash_table_bench.cpp
 *
 * Part of Project c7a.
 *
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <c7a/core/reduce_pre_table.hpp>
#include <c7a/core/reduce_pre_table_bench.hpp>
#include <tests/c7a_tests.hpp>
#include <c7a/api/context.hpp>

#include <functional>
#include <cstdio>

#include "gtest/gtest.h"

struct BenchTable : public::testing::Test {
    std::function<void(int)> emit   = [](int /*in*/){ };
    std::function<int(int)>  key_ex = [](int in){ return in; };
    std::function<int(int, int)> red_fn = [](int in1, int in2){ return in1 + in2; };
};

TEST_F(BenchTable, ActualTable1KKInts) {
    c7a::core::ReducePreTableBench<decltype(key_ex), decltype(red_fn), decltype(emit)>
    table(1, key_ex, red_fn, { emit });

    for (int i = 0; i < 1000000; i++) {
        table.Insert(i * 17);
    }

    table.Flush();
}

TEST_F(BenchTable, ChausTable1KKInts) {
    c7a::core::ReducePreTableBench<decltype(key_ex), decltype(red_fn), decltype(emit)>
    table(1, key_ex, red_fn, { emit });

    for (int i = 0; i < 1000000; i++) {
        table.Insert(i * 17);
    }

    table.Flush();
}

TEST_F(BenchTable, ActualTable10Workers) {
    c7a::core::ReducePreTableBench<decltype(key_ex), decltype(red_fn), decltype(emit)>
    table(10, key_ex, red_fn, { emit });

    for (int i = 0; i < 1000000; i++) {
        table.Insert(i * 17);
    }

    table.Flush();
}

TEST_F(BenchTable, ChausTable10Workers) {
    c7a::core::ReducePreTableBench<decltype(key_ex), decltype(red_fn), decltype(emit)>
    table(10, key_ex, red_fn, { emit });

    for (int i = 0; i < 1000000; i++) {
        table.Insert(i * 17);
    }

    table.Flush();
}

// TODO(ms): add one test with a for loop inserting 10000 items. -> trigger
// resize!

/******************************************************************************/
<commit_msg>Disabled hash_table_bench stuff<commit_after>/*******************************************************************************
 * tests/core/hash_table_bench.cpp
 *
 * Part of Project c7a.
 *
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <c7a/core/reduce_pre_table.hpp>
#include <c7a/core/reduce_pre_table_bench.hpp>
#include <tests/c7a_tests.hpp>
#include <c7a/api/context.hpp>

#include <functional>
#include <cstdio>

#include "gtest/gtest.h"

struct BenchTable : public::testing::Test {
    std::function<void(int)> emit   = [](int /*in*/){ };
    std::function<int(int)>  key_ex = [](int in){ return in; };
    std::function<int(int, int)> red_fn = [](int in1, int in2){ return in1 + in2; };
};

TEST_F(BenchTable, ActualTable1KKInts) {
    c7a::core::ReducePreTableBench<decltype(key_ex), decltype(red_fn), decltype(emit)>
    table(1, key_ex, red_fn, { emit });

    for (int i = 0; i < 1000000; i++) {
        table.Insert(i * 17);
    }

    table.Flush();
}

TEST_F(BenchTable, DISABLED_ChausTable1KKInts) {//I(ts) disabled this test because it does the same as the one above
    c7a::core::ReducePreTableBench<decltype(key_ex), decltype(red_fn), decltype(emit)>
    table(1, key_ex, red_fn, { emit });

    for (int i = 0; i < 1000000; i++) {
        table.Insert(i * 17);
    }

    table.Flush();
}

TEST_F(BenchTable, ActualTable10Workers) {
    c7a::core::ReducePreTableBench<decltype(key_ex), decltype(red_fn), decltype(emit)>
    table(10, key_ex, red_fn, { emit, emit, emit, emit, emit, emit, emit, emit, emit, emit });

    for (int i = 0; i < 1000000; i++) {
        table.Insert(i * 17);
    }

    table.Flush();
}

TEST_F(BenchTable, DISABLED_ChausTable10Workers) {//I(ts) disabled this test because it does the same as the one above

    c7a::core::ReducePreTableBench<decltype(key_ex), decltype(red_fn), decltype(emit)>
    table(10, key_ex, red_fn, { emit });

    for (int i = 0; i < 1000000; i++) {
        table.Insert(i * 17);
    }

    table.Flush();
}

// TODO(ms): add one test with a for loop inserting 10000 items. -> trigger
// resize!

/******************************************************************************/
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------*\
 *                                OpenSG                                     *
 *                                                                           *
 *                                                                           *
 *             Copyright (C) 2000,2001 by the OpenSG Forum                   *
 *                                                                           *
 *                            www.opensg.org                                 *
 *                                                                           *
 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                License                                    *
 *                                                                           *
 * This library is free software; you can redistribute it and/or modify it   *
 * under the terms of the GNU Library General Public License as published    *
 * by the Free Software Foundation, version 2.                               *
 *                                                                           *
 * This library is distributed in the hope that it will be useful, but       *
 * WITHOUT ANY WARRANTY; without even the implied warranty of                *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
 * Library General Public License for more details.                          *
 *                                                                           *
 * You should have received a copy of the GNU Library General Public         *
 * License along with this library; if not, write to the Free Software       *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                Changes                                    *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
\*---------------------------------------------------------------------------*/

//---------------------------------------------------------------------------
//  Includes
//---------------------------------------------------------------------------

#include <OpenSG/OSGGLUT.h>
#include <OpenSG/OSGMatrixUtility.h>
#include <setjmp.h>

#include "TestWindow.h"

// This is ultra-ugly, but GLUT gives you no alternative
static jmp_buf jump;

TestWindow::TestWindow(void) :
    _width(-1), _height(-1), _scene(OSG::NullFC), _window(OSG::NullFC), _ssm(NULL),
    _open(false), _left(0), _right(1), _top(1), _bottom(0),
    _near(0.1), _far(100), _fov(1), _beacon(OSG::NullFC)
{
}

TestWindow::~TestWindow()
{
    if(_window != OSG::NullFC)
        OSG::subRef(_window);
    if(_ssm != NULL)
        delete _ssm;
}

void TestWindow::setFullscreen(void)
{
    if(!isOpen())
    {
        _width = -1;
        return;
    }

    _width = glutGet(GLUT_SCREEN_WIDTH);
    _height = glutGet(GLUT_SCREEN_HEIGHT);

    glutFullScreen();

    if(!setjmp(jump))
        glutMainLoop();

    update();
}

void TestWindow::setSize(OSG::UInt16 width, OSG::UInt16 height)
{
    _width = width;
    _height = height;

    if(isOpen())
    {
        glutReshapeWindow(width, height);

        if(!setjmp(jump))
            glutMainLoop();
    }

    update();
}

void TestWindow::setViewport(OSG::Real32 left,   OSG::Real32 right,
                             OSG::Real32 bottom, OSG::Real32 top   )
{
    _left   = left;
    _right  = right;
    _bottom = bottom;
    _top    = top;

    update();
}

void TestWindow::setCamera(OSG::Matrix mat)
{
    // OSG::beginEditCP(_beacon);
    _beacon->setMatrix(mat);
    // OSG::endEditCP(_beacon);
}

void TestWindow::showAll(void)
{
    update();

    _ssm->showAll();
    _ssm->redraw();
}

void TestWindow::setNearFar(OSG::Real32 n, OSG::Real32 f)
{
    // OSG::beginEditCP(getCamera());
    getCamera()->setNear(n);
    getCamera()->setFar(f);
    // OSG::endEditCP(getCamera());
}

void TestWindow::setFov(OSG::Real32 fov)
{
    // OSG::beginEditCP(getCamera());
    getCamera()->setFov(fov);
    // OSG::endEditCP(getCamera());
}

void TestWindow::redraw(void)
{
//    _ssm->redraw();
    _window->render(dynamic_cast<OSG::RenderAction*>(_ssm->getAction()));
}

OSG::ImagePtr TestWindow::snapshot(void)
{
//    _ssm->redraw();

    OSG::ViewportPtr port = _ssm->getWindow()->getPort(0);

    // OSG::beginEditCP(port);
    port->addForeground(_grabber);
    // OSG::endEditCP(port);

    OSG::ImagePtr img = OSG::Image::create();
    // OSG::beginEditCP(img);
    img->setPixelFormat(OSG::Image::OSG_RGB_PF);
    // OSG::endEditCP(img);

    // OSG::beginEditCP(_grabber);
    _grabber->setImage(img);
    // OSG::endEditCP(_grabber);

    _window->render(dynamic_cast<OSG::RenderAction*>(_ssm->getAction()));

    // OSG::beginEditCP(port);
    port->removeFromForegrounds(port->getForegrounds().size()-1);
    // OSG::endEditCP(port);

    return img;
}

void TestWindow::finish(void)
{
    glFinish();

    OSG::UInt32 dummy;
    glReadPixels(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &dummy);
}

void TestWindow::setCamera(OSG::Real32 fromx, OSG::Real32 fromy, OSG::Real32 fromz,
                           OSG::Real32 atx,   OSG::Real32 aty,   OSG::Real32 atz,
                           OSG::Real32 upx,   OSG::Real32 upy,   OSG::Real32 upz)
{
    OSG::Matrix m;

    OSG::MatrixLookAt(m, fromx, fromy, fromz,
                           atx,   aty,   atz,
                           upx,   upy,   upz);
    setCamera(m);
}

static void display(void)
{
    // Make sure the window is really open...
    glClear(GL_COLOR_BUFFER_BIT);

    glFinish();

    OSG::UInt32 dummy;
    glReadPixels(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &dummy);
}

static void idle(void)
{
    longjmp(jump, 0);
}

void TestWindow::open(void)
{
    static bool inited = false;

    if(isOpen())
        return;

    if(!inited)
    {
        int argc = 2;
        char *argv[2]={"OpenSG", "Benchmarks"};

        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
        inited = true;
    }

    glutInitWindowPosition(0,0);
    if(_width > 0)
        glutInitWindowSize(_width, _height);

    int winid = glutCreateWindow("OpenSG Benchmark");

    if(_width < 0)
    {
        glutFullScreen();
        _width = glutGet(GLUT_SCREEN_WIDTH);
        _height = glutGet(GLUT_SCREEN_HEIGHT);
    }

    glutDisplayFunc(display);
    glutIdleFunc(idle);

    update();

    _window->setId(winid);
    _window->init();

    if(!setjmp(jump))
        glutMainLoop();

    _open = true;
}

void TestWindow::close(void)
{
    glutDestroyWindow(_window->getId());
    _open = false;
}

void TestWindow::update(void)
{
    if(_window == OSG::NullFC)
        _window = OSG::GLUTWindow::create();

    if(_grabber == OSG::NullFC)
    {
        _grabber = OSG::GrabForeground::create();
        // OSG::beginEditCP(_grabber);
        _grabber->setAutoResize(true);
        _grabber->setActive(true);
        // OSG::endEditCP(_grabber);
    }

    if(_ssm == NULL)
        _ssm = new OSG::SimpleSceneManager;

    _ssm->setWindow(_window);

    _ssm->setRoot(_scene);

    _beacon = OSG::cast_dynamic<OSG::TransformPtr>(
                        getCamera()->getBeacon()->getCore());

    _ssm->resize(_width, _height);

    for(int i = 0; i < _ssm->getWindow()->getPort().size(); ++i)
    {
        OSG::ViewportPtr port = _ssm->getWindow()->getPort(i);

        // OSG::beginEditCP(port);
        port->setLeft(_left);
        port->setRight(_right);
        port->setBottom(_bottom);
        port->setTop(_top);
        // OSG::endEditCP(port);
    }

}
<commit_msg>Rendertrav bench bugfix<commit_after>/*---------------------------------------------------------------------------*\
 *                                OpenSG                                     *
 *                                                                           *
 *                                                                           *
 *             Copyright (C) 2000,2001 by the OpenSG Forum                   *
 *                                                                           *
 *                            www.opensg.org                                 *
 *                                                                           *
 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                License                                    *
 *                                                                           *
 * This library is free software; you can redistribute it and/or modify it   *
 * under the terms of the GNU Library General Public License as published    *
 * by the Free Software Foundation, version 2.                               *
 *                                                                           *
 * This library is distributed in the hope that it will be useful, but       *
 * WITHOUT ANY WARRANTY; without even the implied warranty of                *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
 * Library General Public License for more details.                          *
 *                                                                           *
 * You should have received a copy of the GNU Library General Public         *
 * License along with this library; if not, write to the Free Software       *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                Changes                                    *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
\*---------------------------------------------------------------------------*/

//---------------------------------------------------------------------------
//  Includes
//---------------------------------------------------------------------------

#include <OpenSG/OSGGLUT.h>
#include <OpenSG/OSGMatrixUtility.h>
#include <setjmp.h>

#include "TestWindow.h"

// This is ultra-ugly, but GLUT gives you no alternative
static jmp_buf jump;

TestWindow::TestWindow(void) :
    _width(-1), _height(-1), _scene(OSG::NullFC), _window(OSG::NullFC), _ssm(NULL),
    _open(false), _left(0), _right(1), _top(1), _bottom(0),
    _near(0.1), _far(100), _fov(1), _beacon(OSG::NullFC)
{
}

TestWindow::~TestWindow()
{
    if(_window != OSG::NullFC)
        OSG::subRef(_window);
    if(_ssm != NULL)
        delete _ssm;
}

void TestWindow::setFullscreen(void)
{
    if(!isOpen())
    {
        _width = -1;
        return;
    }

    _width = glutGet(GLUT_SCREEN_WIDTH);
    _height = glutGet(GLUT_SCREEN_HEIGHT);

    glutFullScreen();

    if(!setjmp(jump))
        glutMainLoop();

    update();
}

void TestWindow::setSize(OSG::UInt16 width, OSG::UInt16 height)
{
    _width = width;
    _height = height;

    if(isOpen())
    {
        glutReshapeWindow(width, height);

        if(!setjmp(jump))
            glutMainLoop();
    }

    update();
}

void TestWindow::setViewport(OSG::Real32 left,   OSG::Real32 right,
                             OSG::Real32 bottom, OSG::Real32 top   )
{
    _left   = left;
    _right  = right;
    _bottom = bottom;
    _top    = top;

    update();
}

void TestWindow::setCamera(OSG::Matrix mat)
{
    // OSG::beginEditCP(_beacon);
    _beacon->setMatrix(mat);
    // OSG::endEditCP(_beacon);
}

void TestWindow::showAll(void)
{
    update();

    _ssm->showAll();
    _ssm->redraw();
}

void TestWindow::setNearFar(OSG::Real32 n, OSG::Real32 f)
{
    // OSG::beginEditCP(getCamera());
    getCamera()->setNear(n);
    getCamera()->setFar(f);
    // OSG::endEditCP(getCamera());
}

void TestWindow::setFov(OSG::Real32 fov)
{
    // OSG::beginEditCP(getCamera());
    getCamera()->setFov(fov);
    // OSG::endEditCP(getCamera());
}

void TestWindow::redraw(void)
{
//    _ssm->redraw();

    if(!_ssm->getUseTraversalAction())
        _window->render(dynamic_cast<OSG::RenderAction*>(_ssm->getAction()));
#ifdef OSG_CLEANED_RENDERACTION
    else
        _window->render(_ssm->getRenderTraversalAction());
#endif
}

OSG::ImagePtr TestWindow::snapshot(void)
{
//    _ssm->redraw();

    OSG::ViewportPtr port = _ssm->getWindow()->getPort(0);

    // OSG::beginEditCP(port);
    port->addForeground(_grabber);
    // OSG::endEditCP(port);

    OSG::ImagePtr img = OSG::Image::create();
    // OSG::beginEditCP(img);
    img->setPixelFormat(OSG::Image::OSG_RGB_PF);
    // OSG::endEditCP(img);

    // OSG::beginEditCP(_grabber);
    _grabber->setImage(img);
    // OSG::endEditCP(_grabber);

    redraw();

    // OSG::beginEditCP(port);
    port->removeFromForegrounds(port->getForegrounds().size()-1);
    // OSG::endEditCP(port);

    return img;
}

void TestWindow::finish(void)
{
    glFinish();

    OSG::UInt32 dummy;
    glReadPixels(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &dummy);
}

void TestWindow::setCamera(OSG::Real32 fromx, OSG::Real32 fromy, OSG::Real32 fromz,
                           OSG::Real32 atx,   OSG::Real32 aty,   OSG::Real32 atz,
                           OSG::Real32 upx,   OSG::Real32 upy,   OSG::Real32 upz)
{
    OSG::Matrix m;

    OSG::MatrixLookAt(m, fromx, fromy, fromz,
                           atx,   aty,   atz,
                           upx,   upy,   upz);
    setCamera(m);
}

static void display(void)
{
    // Make sure the window is really open...
    glClear(GL_COLOR_BUFFER_BIT);

    glFinish();

    OSG::UInt32 dummy;
    glReadPixels(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &dummy);
}

static void idle(void)
{
    longjmp(jump, 0);
}

void TestWindow::open(void)
{
    static bool inited = false;

    if(isOpen())
        return;

    if(!inited)
    {
        int argc = 2;
        char *argv[2]={"OpenSG", "Benchmarks"};

        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
        inited = true;
    }

    glutInitWindowPosition(0,0);
    if(_width > 0)
        glutInitWindowSize(_width, _height);

    int winid = glutCreateWindow("OpenSG Benchmark");

    if(_width < 0)
    {
        glutFullScreen();
        _width = glutGet(GLUT_SCREEN_WIDTH);
        _height = glutGet(GLUT_SCREEN_HEIGHT);
    }

    glutDisplayFunc(display);
    glutIdleFunc(idle);

    update();

    _window->setId(winid);
    _window->init();

    if(!setjmp(jump))
        glutMainLoop();

    _open = true;
}

void TestWindow::close(void)
{
    glutDestroyWindow(_window->getId());
    _open = false;
}

void TestWindow::update(void)
{
    if(_window == OSG::NullFC)
        _window = OSG::GLUTWindow::create();

    if(_grabber == OSG::NullFC)
    {
        _grabber = OSG::GrabForeground::create();
        // OSG::beginEditCP(_grabber);
        _grabber->setAutoResize(true);
        _grabber->setActive(true);
        // OSG::endEditCP(_grabber);
    }

    if(_ssm == NULL)
        _ssm = new OSG::SimpleSceneManager;

    _ssm->setWindow(_window);

    _ssm->setRoot(_scene);

    _beacon = OSG::cast_dynamic<OSG::TransformPtr>(
                        getCamera()->getBeacon()->getCore());

    _ssm->resize(_width, _height);

    for(int i = 0; i < _ssm->getWindow()->getPort().size(); ++i)
    {
        OSG::ViewportPtr port = _ssm->getWindow()->getPort(i);

        // OSG::beginEditCP(port);
        port->setLeft(_left);
        port->setRight(_right);
        port->setBottom(_bottom);
        port->setTop(_top);
        // OSG::endEditCP(port);
    }

}
<|endoftext|>


<commit_before>/// \file RClusterPool.cxx
/// \ingroup NTuple ROOT7
/// \author Jakob Blomer <jblomer@cern.ch>
/// \date 2020-03-11
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2020, 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 <ROOT/RClusterPool.hxx>
#include <ROOT/RNTupleDescriptor.hxx>
#include <ROOT/RPageStorage.hxx>

#include <TError.h>

#include <algorithm>
#include <chrono>
#include <future>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <utility>

bool ROOT::Experimental::Detail::RClusterPool::RInFlightCluster::operator <(const RInFlightCluster &other) const
{
   if (fClusterId < other.fClusterId)
      return true;
   if (fClusterId > other.fClusterId)
      return false;
   if (fColumns.size() < other.fColumns.size())
      return true;
   if (fColumns.size() > other.fColumns.size())
      return false;
   for (auto itr1 = fColumns.begin(), itr2 = other.fColumns.begin(); itr1 != fColumns.end(); ++itr1, ++itr2) {
      if (*itr1 == *itr2)
         continue;
      return *itr1 < *itr2;
   }
   // *this == other
   return false;
}

ROOT::Experimental::Detail::RClusterPool::RClusterPool(RPageSource *pageSource, unsigned int size)
   : fPageSource(pageSource)
   , fPool(size, nullptr)
   , fThreadIo(&RClusterPool::ExecLoadClusters, this)
{
   R__ASSERT(size > 0);
   fWindowPre = 0;
   fWindowPost = size;
   // Large pools maintain a small look-back window together with the large look-ahead window
   while ((1u << fWindowPre) < (fWindowPost - (fWindowPre + 1))) {
      fWindowPre++;
      fWindowPost--;
   }
}

ROOT::Experimental::Detail::RClusterPool::~RClusterPool()
{
   {
      // Controlled shutdown of the I/O thread
      std::unique_lock<std::mutex> lock(fLockWorkQueue);
      fWorkQueue.emplace(RWorkItem());
      fCvHasWork.notify_one();
   }
   fThreadIo.join();
}

void ROOT::Experimental::Detail::RClusterPool::ExecLoadClusters()
{
   while (true) {
      std::vector<RWorkItem> workItems;
      {
         std::unique_lock<std::mutex> lock(fLockWorkQueue);
         fCvHasWork.wait(lock, [&]{ return !fWorkQueue.empty(); });
         while (!fWorkQueue.empty()) {
            workItems.emplace_back(std::move(fWorkQueue.front()));
            fWorkQueue.pop();
         }
      }

      for (auto &item : workItems) {
         if (item.fClusterId == kInvalidDescriptorId)
            return;

         // TODO(jblomer): the page source needs to be capable of loading multiple clusters in one go
         auto cluster = fPageSource->LoadCluster(item.fClusterId, item.fColumns);

         // Meanwhile, the user might have requested clusters outside the look-ahead window, so that we don't
         // need the cluster anymore, in which case we simply discard it right away, before moving it to the pool
         bool discard = false;
         {
            std::lock_guard<std::mutex> lockGuardInFlightClusters(fLockInFlightClusters);
            for (auto &inFlight : fInFlightClusters) {
               if (inFlight.fClusterId != item.fClusterId)
                  continue;
               discard = inFlight.fIsExpired;
               break;
            }
         }
         if (discard)
            cluster.reset();

         item.fPromise.set_value(std::move(cluster));
      }
   } // while (true)
}

std::shared_ptr<ROOT::Experimental::Detail::RCluster>
ROOT::Experimental::Detail::RClusterPool::FindInPool(DescriptorId_t clusterId)
{
   for (const auto &cptr : fPool) {
      if (cptr && (cptr->GetId() == clusterId))
         return cptr;
   }
   return nullptr;
}

size_t ROOT::Experimental::Detail::RClusterPool::FindFreeSlot() {
   auto N = fPool.size();
   for (unsigned i = 0; i < N; ++i) {
      if (!fPool[i])
         return i;
   }

   R__ASSERT(false);
   return N;
}

namespace {

/// Helper class for the (cluster, column list) pairs that should be loaded in the background
class RProvides {
   using DescriptorId_t = ROOT::Experimental::DescriptorId_t;
   using ColumnSet_t = ROOT::Experimental::Detail::RPageSource::ColumnSet_t;

private:
   std::map<DescriptorId_t, ColumnSet_t> fMap;

public:
   void Insert(DescriptorId_t clusterId, const ColumnSet_t &columns)
   {
      fMap.emplace(clusterId, columns);
   }

   bool Contains(DescriptorId_t clusterId) {
      return fMap.count(clusterId) > 0;
   }

   void Erase(DescriptorId_t clusterId, const ColumnSet_t &columns)
   {
      auto itr = fMap.find(clusterId);
      if (itr == fMap.end())
         return;
      ColumnSet_t d;
      std::set_difference(itr->second.begin(), itr->second.end(), columns.begin(), columns.end(),
                          std::inserter(d, d.end()));
      if (d.empty()) {
         fMap.erase(itr);
      } else {
         itr->second = d;
      }
   }

   decltype(fMap)::iterator begin() { return fMap.begin(); }
   decltype(fMap)::iterator end() { return fMap.end(); }
};

} // anonymous namespace

std::shared_ptr<ROOT::Experimental::Detail::RCluster>
ROOT::Experimental::Detail::RClusterPool::GetCluster(
   DescriptorId_t clusterId, const RPageSource::ColumnSet_t &columns)
{
   const auto &desc = fPageSource->GetDescriptor();

   // Determine previous cluster ids that we keep if they happen to be in the pool
   std::set<DescriptorId_t> keep;
   auto prev = clusterId;
   for (unsigned int i = 0; i < fWindowPre; ++i) {
      prev = desc.FindPrevClusterId(prev);
      if (prev == kInvalidDescriptorId)
         break;
      keep.insert(prev);
   }

   // Determine following cluster ids and the column ids that we want to make available
   RProvides provide;
   provide.Insert(clusterId, columns);
   auto next = clusterId;
   for (unsigned int i = 1; i < fWindowPost; ++i) {
      next = desc.FindNextClusterId(next);
      if (next == kInvalidDescriptorId)
         break;
      provide.Insert(next, columns);
   }

   // Clear the cache from clusters not the in the look-ahead or the look-back window
   for (auto &cptr : fPool) {
      if (!cptr)
         continue;
      if (provide.Contains(cptr->GetId()) > 0)
         continue;
      if (keep.count(cptr->GetId()) > 0)
         continue;
      cptr.reset();
   }

   // Move clusters that meanwhile arrived into cache pool
   {
      std::lock_guard<std::mutex> lockGuardInFlightClusters(fLockInFlightClusters);
      for (auto itr = fInFlightClusters.begin(); itr != fInFlightClusters.end(); ) {
         R__ASSERT(itr->fFuture.valid());
         itr->fIsExpired = !provide.Contains(itr->fClusterId) && (keep.count(itr->fClusterId) == 0);

         if (itr->fFuture.wait_for(std::chrono::seconds(0)) != std::future_status::ready) {
            // Remove the set of columns that are already scheduled for being loaded
            provide.Erase(itr->fClusterId, itr->fColumns);
            ++itr;
            continue;
         }

         auto cptr = itr->fFuture.get();
         // If cptr is nullptr, the cluster expired previously and was released by the I/O thread
         if (!cptr || itr->fIsExpired) {
            cptr.reset();
            itr = fInFlightClusters.erase(itr);
            continue;
         }

         // We either put a fresh cluster into a free slot or we merge the cluster with an existing one
         auto existingCluster = FindInPool(cptr->GetId());
         if (existingCluster) {
            existingCluster->MergeCluster(std::move(*cptr));
         } else {
            auto idxFreeSlot = FindFreeSlot();
            fPool[idxFreeSlot] = std::move(cptr);
         }
         itr = fInFlightClusters.erase(itr);
      }

      // Deterime clusters which get triggered for background loading
      for (auto &cptr : fPool) {
         if (!cptr)
            continue;
         provide.Erase(cptr->GetId(), cptr->GetAvailColumns());
      }

      // Update the work queue and the in-flight cluster list with new requests
      // TODO(jblomer): we should ensure that clusterId is given first to the I/O thread.  That is usually the
      // case but it's not ensured by the code
      std::unique_lock<std::mutex> lockWorkQueue(fLockWorkQueue);
      for (const auto &kv : provide) {
         R__ASSERT(!kv.second.empty());

         RWorkItem workItem;
         workItem.fClusterId = kv.first;
         workItem.fColumns = kv.second;

         RInFlightCluster inFlightCluster;
         inFlightCluster.fClusterId = kv.first;
         inFlightCluster.fColumns = kv.second;
         inFlightCluster.fFuture = workItem.fPromise.get_future();
         fInFlightClusters.emplace_back(std::move(inFlightCluster));

         fWorkQueue.emplace(std::move(workItem));
      }
      if (fWorkQueue.size() > 0)
         fCvHasWork.notify_one();
   } // work queue and in-flight clusters lock guards

   return WaitFor(clusterId, columns);
}

std::shared_ptr<ROOT::Experimental::Detail::RCluster>
ROOT::Experimental::Detail::RClusterPool::WaitFor(
   DescriptorId_t clusterId, const RPageSource::ColumnSet_t &columns)
{
   while (true) {
      // Fast exit: the cluster happens to be already present in the cache pool
      auto result = FindInPool(clusterId);
      if (result) {
         bool hasMissingColumn = false;
         for (auto cid : columns) {
            if (result->ContainsColumn(cid))
               continue;

            hasMissingColumn = true;
            break;
         }
         if (!hasMissingColumn)
            return result;
      }

      // Otherwise the missing data must have been triggered for loading by now, so block and wait
      auto itr = fInFlightClusters.begin();
      for (; itr != fInFlightClusters.end(); ++itr) {
         if (itr->fClusterId == clusterId)
            break;
      }
      R__ASSERT(itr != fInFlightClusters.end());

      auto cptr = itr->fFuture.get();
      if (result) {
         result->MergeCluster(std::move(*cptr));
      } else {
         auto idxFreeSlot = FindFreeSlot();
         fPool[idxFreeSlot] = std::move(cptr);
      }

      std::lock_guard<std::mutex> lockGuardInFlightClusters(fLockInFlightClusters);
      fInFlightClusters.erase(itr);
   }
}
<commit_msg>[ntuple] fix typo (NFC)<commit_after>/// \file RClusterPool.cxx
/// \ingroup NTuple ROOT7
/// \author Jakob Blomer <jblomer@cern.ch>
/// \date 2020-03-11
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2020, 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 <ROOT/RClusterPool.hxx>
#include <ROOT/RNTupleDescriptor.hxx>
#include <ROOT/RPageStorage.hxx>

#include <TError.h>

#include <algorithm>
#include <chrono>
#include <future>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <utility>

bool ROOT::Experimental::Detail::RClusterPool::RInFlightCluster::operator <(const RInFlightCluster &other) const
{
   if (fClusterId < other.fClusterId)
      return true;
   if (fClusterId > other.fClusterId)
      return false;
   if (fColumns.size() < other.fColumns.size())
      return true;
   if (fColumns.size() > other.fColumns.size())
      return false;
   for (auto itr1 = fColumns.begin(), itr2 = other.fColumns.begin(); itr1 != fColumns.end(); ++itr1, ++itr2) {
      if (*itr1 == *itr2)
         continue;
      return *itr1 < *itr2;
   }
   // *this == other
   return false;
}

ROOT::Experimental::Detail::RClusterPool::RClusterPool(RPageSource *pageSource, unsigned int size)
   : fPageSource(pageSource)
   , fPool(size, nullptr)
   , fThreadIo(&RClusterPool::ExecLoadClusters, this)
{
   R__ASSERT(size > 0);
   fWindowPre = 0;
   fWindowPost = size;
   // Large pools maintain a small look-back window together with the large look-ahead window
   while ((1u << fWindowPre) < (fWindowPost - (fWindowPre + 1))) {
      fWindowPre++;
      fWindowPost--;
   }
}

ROOT::Experimental::Detail::RClusterPool::~RClusterPool()
{
   {
      // Controlled shutdown of the I/O thread
      std::unique_lock<std::mutex> lock(fLockWorkQueue);
      fWorkQueue.emplace(RWorkItem());
      fCvHasWork.notify_one();
   }
   fThreadIo.join();
}

void ROOT::Experimental::Detail::RClusterPool::ExecLoadClusters()
{
   while (true) {
      std::vector<RWorkItem> workItems;
      {
         std::unique_lock<std::mutex> lock(fLockWorkQueue);
         fCvHasWork.wait(lock, [&]{ return !fWorkQueue.empty(); });
         while (!fWorkQueue.empty()) {
            workItems.emplace_back(std::move(fWorkQueue.front()));
            fWorkQueue.pop();
         }
      }

      for (auto &item : workItems) {
         if (item.fClusterId == kInvalidDescriptorId)
            return;

         // TODO(jblomer): the page source needs to be capable of loading multiple clusters in one go
         auto cluster = fPageSource->LoadCluster(item.fClusterId, item.fColumns);

         // Meanwhile, the user might have requested clusters outside the look-ahead window, so that we don't
         // need the cluster anymore, in which case we simply discard it right away, before moving it to the pool
         bool discard = false;
         {
            std::lock_guard<std::mutex> lockGuardInFlightClusters(fLockInFlightClusters);
            for (auto &inFlight : fInFlightClusters) {
               if (inFlight.fClusterId != item.fClusterId)
                  continue;
               discard = inFlight.fIsExpired;
               break;
            }
         }
         if (discard)
            cluster.reset();

         item.fPromise.set_value(std::move(cluster));
      }
   } // while (true)
}

std::shared_ptr<ROOT::Experimental::Detail::RCluster>
ROOT::Experimental::Detail::RClusterPool::FindInPool(DescriptorId_t clusterId)
{
   for (const auto &cptr : fPool) {
      if (cptr && (cptr->GetId() == clusterId))
         return cptr;
   }
   return nullptr;
}

size_t ROOT::Experimental::Detail::RClusterPool::FindFreeSlot() {
   auto N = fPool.size();
   for (unsigned i = 0; i < N; ++i) {
      if (!fPool[i])
         return i;
   }

   R__ASSERT(false);
   return N;
}

namespace {

/// Helper class for the (cluster, column list) pairs that should be loaded in the background
class RProvides {
   using DescriptorId_t = ROOT::Experimental::DescriptorId_t;
   using ColumnSet_t = ROOT::Experimental::Detail::RPageSource::ColumnSet_t;

private:
   std::map<DescriptorId_t, ColumnSet_t> fMap;

public:
   void Insert(DescriptorId_t clusterId, const ColumnSet_t &columns)
   {
      fMap.emplace(clusterId, columns);
   }

   bool Contains(DescriptorId_t clusterId) {
      return fMap.count(clusterId) > 0;
   }

   void Erase(DescriptorId_t clusterId, const ColumnSet_t &columns)
   {
      auto itr = fMap.find(clusterId);
      if (itr == fMap.end())
         return;
      ColumnSet_t d;
      std::set_difference(itr->second.begin(), itr->second.end(), columns.begin(), columns.end(),
                          std::inserter(d, d.end()));
      if (d.empty()) {
         fMap.erase(itr);
      } else {
         itr->second = d;
      }
   }

   decltype(fMap)::iterator begin() { return fMap.begin(); }
   decltype(fMap)::iterator end() { return fMap.end(); }
};

} // anonymous namespace

std::shared_ptr<ROOT::Experimental::Detail::RCluster>
ROOT::Experimental::Detail::RClusterPool::GetCluster(
   DescriptorId_t clusterId, const RPageSource::ColumnSet_t &columns)
{
   const auto &desc = fPageSource->GetDescriptor();

   // Determine previous cluster ids that we keep if they happen to be in the pool
   std::set<DescriptorId_t> keep;
   auto prev = clusterId;
   for (unsigned int i = 0; i < fWindowPre; ++i) {
      prev = desc.FindPrevClusterId(prev);
      if (prev == kInvalidDescriptorId)
         break;
      keep.insert(prev);
   }

   // Determine following cluster ids and the column ids that we want to make available
   RProvides provide;
   provide.Insert(clusterId, columns);
   auto next = clusterId;
   for (unsigned int i = 1; i < fWindowPost; ++i) {
      next = desc.FindNextClusterId(next);
      if (next == kInvalidDescriptorId)
         break;
      provide.Insert(next, columns);
   }

   // Clear the cache from clusters not the in the look-ahead or the look-back window
   for (auto &cptr : fPool) {
      if (!cptr)
         continue;
      if (provide.Contains(cptr->GetId()) > 0)
         continue;
      if (keep.count(cptr->GetId()) > 0)
         continue;
      cptr.reset();
   }

   // Move clusters that meanwhile arrived into cache pool
   {
      std::lock_guard<std::mutex> lockGuardInFlightClusters(fLockInFlightClusters);
      for (auto itr = fInFlightClusters.begin(); itr != fInFlightClusters.end(); ) {
         R__ASSERT(itr->fFuture.valid());
         itr->fIsExpired = !provide.Contains(itr->fClusterId) && (keep.count(itr->fClusterId) == 0);

         if (itr->fFuture.wait_for(std::chrono::seconds(0)) != std::future_status::ready) {
            // Remove the set of columns that are already scheduled for being loaded
            provide.Erase(itr->fClusterId, itr->fColumns);
            ++itr;
            continue;
         }

         auto cptr = itr->fFuture.get();
         // If cptr is nullptr, the cluster expired previously and was released by the I/O thread
         if (!cptr || itr->fIsExpired) {
            cptr.reset();
            itr = fInFlightClusters.erase(itr);
            continue;
         }

         // We either put a fresh cluster into a free slot or we merge the cluster with an existing one
         auto existingCluster = FindInPool(cptr->GetId());
         if (existingCluster) {
            existingCluster->MergeCluster(std::move(*cptr));
         } else {
            auto idxFreeSlot = FindFreeSlot();
            fPool[idxFreeSlot] = std::move(cptr);
         }
         itr = fInFlightClusters.erase(itr);
      }

      // Determine clusters which get triggered for background loading
      for (auto &cptr : fPool) {
         if (!cptr)
            continue;
         provide.Erase(cptr->GetId(), cptr->GetAvailColumns());
      }

      // Update the work queue and the in-flight cluster list with new requests
      // TODO(jblomer): we should ensure that clusterId is given first to the I/O thread.  That is usually the
      // case but it's not ensured by the code
      std::unique_lock<std::mutex> lockWorkQueue(fLockWorkQueue);
      for (const auto &kv : provide) {
         R__ASSERT(!kv.second.empty());

         RWorkItem workItem;
         workItem.fClusterId = kv.first;
         workItem.fColumns = kv.second;

         RInFlightCluster inFlightCluster;
         inFlightCluster.fClusterId = kv.first;
         inFlightCluster.fColumns = kv.second;
         inFlightCluster.fFuture = workItem.fPromise.get_future();
         fInFlightClusters.emplace_back(std::move(inFlightCluster));

         fWorkQueue.emplace(std::move(workItem));
      }
      if (fWorkQueue.size() > 0)
         fCvHasWork.notify_one();
   } // work queue and in-flight clusters lock guards

   return WaitFor(clusterId, columns);
}

std::shared_ptr<ROOT::Experimental::Detail::RCluster>
ROOT::Experimental::Detail::RClusterPool::WaitFor(
   DescriptorId_t clusterId, const RPageSource::ColumnSet_t &columns)
{
   while (true) {
      // Fast exit: the cluster happens to be already present in the cache pool
      auto result = FindInPool(clusterId);
      if (result) {
         bool hasMissingColumn = false;
         for (auto cid : columns) {
            if (result->ContainsColumn(cid))
               continue;

            hasMissingColumn = true;
            break;
         }
         if (!hasMissingColumn)
            return result;
      }

      // Otherwise the missing data must have been triggered for loading by now, so block and wait
      auto itr = fInFlightClusters.begin();
      for (; itr != fInFlightClusters.end(); ++itr) {
         if (itr->fClusterId == clusterId)
            break;
      }
      R__ASSERT(itr != fInFlightClusters.end());

      auto cptr = itr->fFuture.get();
      if (result) {
         result->MergeCluster(std::move(*cptr));
      } else {
         auto idxFreeSlot = FindFreeSlot();
         fPool[idxFreeSlot] = std::move(cptr);
      }

      std::lock_guard<std::mutex> lockGuardInFlightClusters(fLockInFlightClusters);
      fInFlightClusters.erase(itr);
   }
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2011.  All rights reserved
 */
#include	"../StroikaPreComp.h"

#include	"../Containers/Common.h"

#include	"TextInputStream.h"

using	namespace	Stroika::Foundation;
using	namespace	Stroika::Foundation::Streams;

/*
 ********************************************************************************
 ************************** Streams::TextInputStream ****************************
 ********************************************************************************
 */
<commit_msg>add needed includes<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2011.  All rights reserved
 */
#include	"../StroikaPreComp.h"

#include <stdlib.h>

#include <algorithm>

#include	"../Containers/Common.h"

#include	"TextInputStream.h"

using	namespace	Stroika::Foundation;
using	namespace	Stroika::Foundation::Streams;

/*
 ********************************************************************************
 ************************** Streams::TextInputStream ****************************
 ********************************************************************************
 */
<|endoftext|>


<commit_before><commit_msg>tweak<commit_after><|endoftext|>


<commit_before>
#ifndef AT_TIMER_HPP
#define AT_TIMER_HPP

class atTimer
{
   private:

      static atTimer    *systemTimer;

      double            markTime;
      double            markInterval;

   public:

      atTimer();
      ~atTimer();

      void              mark();
      void              markAtInterval(double intervalTime);
      double            getInterval();
      double            getElapsed();
};

#endif
<commit_msg>Made atTimer inherit from atNotifier, as all ATLAS objects do<commit_after>
#ifndef AT_TIMER_HPP
#define AT_TIMER_HPP

#include "atNotifier.h++"

class atTimer : public atNotifier
{
   private:

      static atTimer    *systemTimer;

      double            markTime;
      double            markInterval;

   public:

      atTimer();
      ~atTimer();

      void              mark();
      void              markAtInterval(double intervalTime);
      double            getInterval();
      double            getElapsed();
};

#endif
<|endoftext|>