<commit_before>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 *
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once
namespace sstables {
class malformed_sstable_exception : public std::exception {
    sstring _msg;
public:
    malformed_sstable_exception(sstring s)
        : std::exception()
        , _msg(s) {}
    const char *what() const noexcept {
        return _msg.c_str();
    }
};

struct bufsize_mismatch_exception : malformed_sstable_exception {
    bufsize_mismatch_exception(size_t size, size_t expected) :
        malformed_sstable_exception(sprint("Buffer improperly sized to hold requested data. Got: %ld. Expected: %ld", size, expected))
    {}
};
}
<commit_msg>Revert "sstable: Initialize super class of malformed_sstable_exception"<commit_after>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 *
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once
namespace sstables {
class malformed_sstable_exception : public std::exception {
    sstring _msg;
public:
    malformed_sstable_exception(sstring s) : _msg(s) {}
    const char *what() const noexcept {
        return _msg.c_str();
    }
};

struct bufsize_mismatch_exception : malformed_sstable_exception {
    bufsize_mismatch_exception(size_t size, size_t expected) :
        malformed_sstable_exception(sprint("Buffer improperly sized to hold requested data. Got: %ld. Expected: %ld", size, expected))
    {}
};
}
<|endoftext|>


<commit_before>// @(#)root/io:$Id$
// Author: Philippe Canal, Witold Pokorski, and Guilherme Amadio

/*************************************************************************
 * Copyright (C) 1995-2017, 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/TBufferMerger.hxx"

#include "TBufferFile.h"
#include "TError.h"
#include "TFileMerger.h"
#include "TROOT.h"
#include "TVirtualMutex.h"

namespace ROOT {
namespace Experimental {

TBufferMerger::TBufferMerger(const char *name, Option_t *option, Int_t compress)
{
   // NOTE: We cannot use ctor chaining or in-place initialization because we want this operation to have no effect on
   // ROOT's gDirectory.
   TDirectory::TContext ctxt;
   if (TFile *output = TFile::Open(name, option, /*title*/ name, compress))
      Init(std::unique_ptr<TFile>(output));
   else
      Error("OutputFile", "cannot open the MERGER output file %s", name);
}

TBufferMerger::TBufferMerger(std::unique_ptr<TFile> output)
{
   Init(std::move(output));
}

void TBufferMerger::Init(std::unique_ptr<TFile> output)
{
   fFile = output.release();
   fAutoSave = 0;
   fMergingThread.reset(new std::thread([&]() { this->WriteOutputFile(); }));
}

TBufferMerger::~TBufferMerger()
{
   for (auto f : fAttachedFiles)
      if (!f.expired()) Fatal("TBufferMerger", " TBufferMergerFiles must be destroyed before the server");

   this->Push(nullptr);
   fMergingThread->join();
}

std::shared_ptr<TBufferMergerFile> TBufferMerger::GetFile()
{
   R__LOCKGUARD(gROOTMutex);
   std::shared_ptr<TBufferMergerFile> f(new TBufferMergerFile(*this));
   gROOT->GetListOfFiles()->Remove(f.get());
   fAttachedFiles.push_back(f);
   return f;
}

size_t TBufferMerger::GetQueueSize() const
{
   return fQueue.size();
}

void TBufferMerger::RegisterCallback(const std::function<void(void)> &f)
{
   fCallback = f;
}

void TBufferMerger::Push(TBufferFile *buffer)
{
   {
      std::lock_guard<std::mutex> lock(fQueueMutex);
      fQueue.push(buffer);
   }
   fDataAvailable.notify_one();
}

size_t TBufferMerger::GetAutoSave() const
{
   return fAutoSave;
}

void TBufferMerger::SetAutoSave(size_t size)
{
   fAutoSave = size;
}

void TBufferMerger::WriteOutputFile()
{
   size_t buffered = 0;
   TFileMerger merger;
   std::unique_ptr<TBufferFile> buffer;
   std::vector<std::unique_ptr<TMemFile>> memfiles;

   merger.ResetBit(kMustCleanup);

   {
      R__LOCKGUARD(gROOTMutex);
      merger.OutputFile(std::unique_ptr<TFile>(fFile));
   }

   while (true) {
      std::unique_lock<std::mutex> lock(fQueueMutex);
      fDataAvailable.wait(lock, [this]() { return !this->fQueue.empty(); });

      buffer.reset(fQueue.front());
      fQueue.pop();
      lock.unlock();

      if (!buffer)
         break;

      Long64_t length;
      buffer->SetReadMode();
      buffer->SetBufferOffset();
      buffer->ReadLong64(length);
      buffered += length;

      memfiles.emplace_back(new TMemFile(fFile->GetName(), buffer->Buffer() + buffer->Length(), length, "read"));
      merger.AddFile(memfiles.back().get(), false);

      if (buffered > fAutoSave) {
         buffered = 0;
         merger.PartialMerge();
         merger.Reset();
         memfiles.clear();
      }

      if (fCallback)
         fCallback();
   }

   R__LOCKGUARD(gROOTMutex);
   merger.PartialMerge();
   merger.Reset();
}

} // namespace Experimental
} // namespace ROOT
<commit_msg>Update comment to use shorter lines<commit_after>// @(#)root/io:$Id$
// Author: Philippe Canal, Witold Pokorski, and Guilherme Amadio

/*************************************************************************
 * Copyright (C) 1995-2017, 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/TBufferMerger.hxx"

#include "TBufferFile.h"
#include "TError.h"
#include "TFileMerger.h"
#include "TROOT.h"
#include "TVirtualMutex.h"

namespace ROOT {
namespace Experimental {

TBufferMerger::TBufferMerger(const char *name, Option_t *option, Int_t compress)
{
   // We cannot chain constructors or use in-place initialization here because
   // instantiating a TBufferMerger should not alter gDirectory's state.
   TDirectory::TContext ctxt;
   if (TFile *output = TFile::Open(name, option, /*title*/ name, compress))
      Init(std::unique_ptr<TFile>(output));
   else
      Error("OutputFile", "cannot open the MERGER output file %s", name);
}

TBufferMerger::TBufferMerger(std::unique_ptr<TFile> output)
{
   Init(std::move(output));
}

void TBufferMerger::Init(std::unique_ptr<TFile> output)
{
   fFile = output.release();
   fAutoSave = 0;
   fMergingThread.reset(new std::thread([&]() { this->WriteOutputFile(); }));
}

TBufferMerger::~TBufferMerger()
{
   for (auto f : fAttachedFiles)
      if (!f.expired()) Fatal("TBufferMerger", " TBufferMergerFiles must be destroyed before the server");

   this->Push(nullptr);
   fMergingThread->join();
}

std::shared_ptr<TBufferMergerFile> TBufferMerger::GetFile()
{
   R__LOCKGUARD(gROOTMutex);
   std::shared_ptr<TBufferMergerFile> f(new TBufferMergerFile(*this));
   gROOT->GetListOfFiles()->Remove(f.get());
   fAttachedFiles.push_back(f);
   return f;
}

size_t TBufferMerger::GetQueueSize() const
{
   return fQueue.size();
}

void TBufferMerger::RegisterCallback(const std::function<void(void)> &f)
{
   fCallback = f;
}

void TBufferMerger::Push(TBufferFile *buffer)
{
   {
      std::lock_guard<std::mutex> lock(fQueueMutex);
      fQueue.push(buffer);
   }
   fDataAvailable.notify_one();
}

size_t TBufferMerger::GetAutoSave() const
{
   return fAutoSave;
}

void TBufferMerger::SetAutoSave(size_t size)
{
   fAutoSave = size;
}

void TBufferMerger::WriteOutputFile()
{
   size_t buffered = 0;
   TFileMerger merger;
   std::unique_ptr<TBufferFile> buffer;
   std::vector<std::unique_ptr<TMemFile>> memfiles;

   merger.ResetBit(kMustCleanup);

   {
      R__LOCKGUARD(gROOTMutex);
      merger.OutputFile(std::unique_ptr<TFile>(fFile));
   }

   while (true) {
      std::unique_lock<std::mutex> lock(fQueueMutex);
      fDataAvailable.wait(lock, [this]() { return !this->fQueue.empty(); });

      buffer.reset(fQueue.front());
      fQueue.pop();
      lock.unlock();

      if (!buffer)
         break;

      Long64_t length;
      buffer->SetReadMode();
      buffer->SetBufferOffset();
      buffer->ReadLong64(length);
      buffered += length;

      memfiles.emplace_back(new TMemFile(fFile->GetName(), buffer->Buffer() + buffer->Length(), length, "read"));
      merger.AddFile(memfiles.back().get(), false);

      if (buffered > fAutoSave) {
         buffered = 0;
         merger.PartialMerge();
         merger.Reset();
         memfiles.clear();
      }

      if (fCallback)
         fCallback();
   }

   R__LOCKGUARD(gROOTMutex);
   merger.PartialMerge();
   merger.Reset();
}

} // namespace Experimental
} // namespace ROOT
<|endoftext|>


<commit_before>//===------------------------ iostream.cpp --------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "__std_stream"
#include "string"
#include "new"

_LIBCPP_BEGIN_NAMESPACE_STD

#ifndef _LIBCPP_HAS_NO_STDIN
_ALIGNAS_TYPE (istream)  _LIBCPP_FUNC_VIS char cin [sizeof(istream)];
_ALIGNAS_TYPE (__stdinbuf<char> ) static char __cin [sizeof(__stdinbuf <char>)];
static mbstate_t mb_cin;
_ALIGNAS_TYPE (wistream) _LIBCPP_FUNC_VIS char wcin [sizeof(wistream)];
_ALIGNAS_TYPE (__stdinbuf<wchar_t> ) static char __wcin [sizeof(__stdinbuf <wchar_t>)];
static mbstate_t mb_wcin;
#endif

#ifndef _LIBCPP_HAS_NO_STDOUT
_ALIGNAS_TYPE (ostream)  _LIBCPP_FUNC_VIS char cout[sizeof(ostream)];
_ALIGNAS_TYPE (__stdoutbuf<char>) static char __cout[sizeof(__stdoutbuf<char>)];
static mbstate_t mb_cout;
_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wcout[sizeof(wostream)];
_ALIGNAS_TYPE (__stdoutbuf<wchar_t>) static char __wcout[sizeof(__stdoutbuf<wchar_t>)];
static mbstate_t mb_wcout;
#endif

_ALIGNAS_TYPE (ostream)  _LIBCPP_FUNC_VIS char cerr[sizeof(ostream)];
_ALIGNAS_TYPE (__stdoutbuf<char>) static char __cerr[sizeof(__stdoutbuf<char>)];
static mbstate_t mb_cerr;
_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wcerr[sizeof(wostream)];
_ALIGNAS_TYPE (__stdoutbuf<wchar_t>) static char __wcerr[sizeof(__stdoutbuf<wchar_t>)];
static mbstate_t mb_wcerr;

_ALIGNAS_TYPE (ostream)  _LIBCPP_FUNC_VIS char clog[sizeof(ostream)];
_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wclog[sizeof(wostream)];

ios_base::Init __start_std_streams;

ios_base::Init::Init()
{
#ifndef _LIBCPP_HAS_NO_STDIN
    istream* cin_ptr  = ::new(cin)  istream(::new(__cin)  __stdinbuf <char>(stdin, &mb_cin));
    wistream* wcin_ptr  = ::new(wcin)  wistream(::new(__wcin)  __stdinbuf <wchar_t>(stdin, &mb_wcin));
#endif
#ifndef _LIBCPP_HAS_NO_STDOUT
    ostream* cout_ptr = ::new(cout) ostream(::new(__cout) __stdoutbuf<char>(stdout, &mb_cout));
    wostream* wcout_ptr = ::new(wcout) wostream(::new(__wcout) __stdoutbuf<wchar_t>(stdout, &mb_wcout));
#endif
    ostream* cerr_ptr = ::new(cerr) ostream(::new(__cerr) __stdoutbuf<char>(stderr, &mb_cerr));
                        ::new(clog) ostream(cerr_ptr->rdbuf());
    wostream* wcerr_ptr = ::new(wcerr) wostream(::new(__wcerr) __stdoutbuf<wchar_t>(stderr, &mb_wcerr));
                          ::new(wclog) wostream(wcerr_ptr->rdbuf());

#if !defined(_LIBCPP_HAS_NO_STDIN) && !defined(_LIBCPP_HAS_NO_STDOUT)
    cin_ptr->tie(cout_ptr);
    wcin_ptr->tie(wcout_ptr);
#endif
    _VSTD::unitbuf(*cerr_ptr);
    _VSTD::unitbuf(*wcerr_ptr);
#ifndef _LIBCPP_HAS_NO_STDOUT
    cerr_ptr->tie(cout_ptr);
    wcerr_ptr->tie(wcout_ptr);
#endif
}

ios_base::Init::~Init()
{
#ifndef _LIBCPP_HAS_NO_STDOUT
    ostream* cout_ptr = reinterpret_cast<ostream*>(cout);
    wostream* wcout_ptr = reinterpret_cast<wostream*>(wcout);
    cout_ptr->flush();
    wcout_ptr->flush();
#endif

    ostream* clog_ptr = reinterpret_cast<ostream*>(clog);
    wostream* wclog_ptr = reinterpret_cast<wostream*>(wclog);
    clog_ptr->flush();
    wclog_ptr->flush();
}

_LIBCPP_END_NAMESPACE_STD
<commit_msg>Explicitly specify MSVC mangling of iostream globals. Patch from Dave Lee<commit_after>//===------------------------ iostream.cpp --------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "__std_stream"
#include "string"
#include "new"

_LIBCPP_BEGIN_NAMESPACE_STD

#ifndef _LIBCPP_HAS_NO_STDIN
_ALIGNAS_TYPE (istream) _LIBCPP_FUNC_VIS char cin[sizeof(istream)]
#if defined(_MSC_VER) && defined(__clang__)
__asm__("?cin@__1@std@@3V?$basic_istream@DU?$char_traits@D@__1@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdinbuf<char> ) static char __cin[sizeof(__stdinbuf <char>)];
static mbstate_t mb_cin;
_ALIGNAS_TYPE (wistream) _LIBCPP_FUNC_VIS char wcin[sizeof(wistream)]
#if defined(_MSC_VER) && defined(__clang__)
__asm__("?wcin@__1@std@@3V?$basic_istream@_WU?$char_traits@_W@__1@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdinbuf<wchar_t> ) static char __wcin[sizeof(__stdinbuf <wchar_t>)];
static mbstate_t mb_wcin;
#endif

#ifndef _LIBCPP_HAS_NO_STDOUT
_ALIGNAS_TYPE (ostream) _LIBCPP_FUNC_VIS char cout[sizeof(ostream)]
#if defined(_MSC_VER) && defined(__clang__)
__asm__("?cout@__1@std@@3V?$basic_ostream@DU?$char_traits@D@__1@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdoutbuf<char>) static char __cout[sizeof(__stdoutbuf<char>)];
static mbstate_t mb_cout;
_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wcout[sizeof(wostream)]
#if defined(_MSC_VER) && defined(__clang__)
__asm__("?wcout@__1@std@@3V?$basic_ostream@_WU?$char_traits@_W@__1@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdoutbuf<wchar_t>) static char __wcout[sizeof(__stdoutbuf<wchar_t>)];
static mbstate_t mb_wcout;
#endif

_ALIGNAS_TYPE (ostream) _LIBCPP_FUNC_VIS char cerr[sizeof(ostream)]
#if defined(_MSC_VER) && defined(__clang__)
__asm__("?cerr@__1@std@@3V?$basic_ostream@DU?$char_traits@D@__1@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdoutbuf<char>) static char __cerr[sizeof(__stdoutbuf<char>)];
static mbstate_t mb_cerr;
_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wcerr[sizeof(wostream)]
#if defined(_MSC_VER) && defined(__clang__)
__asm__("?wcerr@__1@std@@3V?$basic_ostream@_WU?$char_traits@_W@__1@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (__stdoutbuf<wchar_t>) static char __wcerr[sizeof(__stdoutbuf<wchar_t>)];
static mbstate_t mb_wcerr;

_ALIGNAS_TYPE (ostream) _LIBCPP_FUNC_VIS char clog[sizeof(ostream)]
#if defined(_MSC_VER) && defined(__clang__)
__asm__("?clog@__1@std@@3V?$basic_ostream@DU?$char_traits@D@__1@std@@@12@A")
#endif
;
_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wclog[sizeof(wostream)]
#if defined(_MSC_VER) && defined(__clang__)
__asm__("?wclog@__1@std@@3V?$basic_ostream@_WU?$char_traits@_W@__1@std@@@12@A")
#endif
;

ios_base::Init __start_std_streams;

ios_base::Init::Init()
{
#ifndef _LIBCPP_HAS_NO_STDIN
    istream* cin_ptr  = ::new(cin)  istream(::new(__cin)  __stdinbuf <char>(stdin, &mb_cin));
    wistream* wcin_ptr  = ::new(wcin)  wistream(::new(__wcin)  __stdinbuf <wchar_t>(stdin, &mb_wcin));
#endif
#ifndef _LIBCPP_HAS_NO_STDOUT
    ostream* cout_ptr = ::new(cout) ostream(::new(__cout) __stdoutbuf<char>(stdout, &mb_cout));
    wostream* wcout_ptr = ::new(wcout) wostream(::new(__wcout) __stdoutbuf<wchar_t>(stdout, &mb_wcout));
#endif
    ostream* cerr_ptr = ::new(cerr) ostream(::new(__cerr) __stdoutbuf<char>(stderr, &mb_cerr));
                        ::new(clog) ostream(cerr_ptr->rdbuf());
    wostream* wcerr_ptr = ::new(wcerr) wostream(::new(__wcerr) __stdoutbuf<wchar_t>(stderr, &mb_wcerr));
                          ::new(wclog) wostream(wcerr_ptr->rdbuf());

#if !defined(_LIBCPP_HAS_NO_STDIN) && !defined(_LIBCPP_HAS_NO_STDOUT)
    cin_ptr->tie(cout_ptr);
    wcin_ptr->tie(wcout_ptr);
#endif
    _VSTD::unitbuf(*cerr_ptr);
    _VSTD::unitbuf(*wcerr_ptr);
#ifndef _LIBCPP_HAS_NO_STDOUT
    cerr_ptr->tie(cout_ptr);
    wcerr_ptr->tie(wcout_ptr);
#endif
}

ios_base::Init::~Init()
{
#ifndef _LIBCPP_HAS_NO_STDOUT
    ostream* cout_ptr = reinterpret_cast<ostream*>(cout);
    wostream* wcout_ptr = reinterpret_cast<wostream*>(wcout);
    cout_ptr->flush();
    wcout_ptr->flush();
#endif

    ostream* clog_ptr = reinterpret_cast<ostream*>(clog);
    wostream* wclog_ptr = reinterpret_cast<wostream*>(wclog);
    clog_ptr->flush();
    wclog_ptr->flush();
}

_LIBCPP_END_NAMESPACE_STD
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// index_scan_plan.cpp
//
// Identification: src/planner/index_scan_plan.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "planner/index_scan_plan.h"
#include "expression/constant_value_expression.h"
#include "expression/expression_util.h"
#include "storage/data_table.h"
#include "type/types.h"

namespace peloton {
namespace planner {

IndexScanPlan::IndexScanPlan(storage::DataTable *table,
                             expression::AbstractExpression *predicate,
                             const std::vector<oid_t> &column_ids,
                             const IndexScanDesc &index_scan_desc,
                             bool for_update_flag)
    : index_(index_scan_desc.index_obj),
      column_ids_(column_ids),
      key_column_ids_(std::move(index_scan_desc.tuple_column_id_list)),
      expr_types_(std::move(index_scan_desc.expr_list)),
      values_with_params_(std::move(index_scan_desc.value_list)),
      runtime_keys_(std::move(index_scan_desc.runtime_key_list)),
      // Initialize the index scan predicate object and initialize all
      // keys that we could initialize
      index_predicate_() {
  LOG_TRACE("Creating an Index Scan Plan");

  if (for_update_flag == true) {
    SetForUpdateFlag(true);
  }

  SetTargetTable(table);

  if (predicate != NULL) {
    // we need to copy it here because eventually predicate will be destroyed by
    // its owner...
    predicate = predicate->Copy();
    expression::ExpressionUtil::TransformExpression(table->GetSchema(),
                                                    predicate);
    SetPredicate(predicate);
  }

  // copy the value over for binding purpose
  for (auto val : values_with_params_) {
    values_.push_back(val.Copy());
  }

  // Then add the only conjunction predicate into the index predicate list
  // (at least for now we only supports single conjunction)
  index_predicate_.AddConjunctionScanPredicate(index_.get(), values_,
                                               key_column_ids_, expr_types_);

  return;
}

void IndexScanPlan::SetParameterValues(std::vector<type::Value> *values) {
  LOG_TRACE("Setting parameter values in Index Scans");

  // Destroy the values of the last plan and copy the original values over for
  // binding
  values_.clear();
  for (auto val : values_with_params_) {
    values_.push_back(val.Copy());
  }

  for (unsigned int i = 0; i < values_.size(); ++i) {
    auto value = values_[i];
    auto column_id = key_column_ids_[i];
    if (value.GetTypeId() == type::Type::PARAMETER_OFFSET) {
      int offset = value.GetAs<int32_t>();
      values_[i] =
          (values->at(offset))
              .CastAs(GetTable()->GetSchema()->GetColumn(column_id).GetType());
    }
  }

  // Also bind values to index scan predicate object
  //
  // NOTE: This could only be called by one thread at a time
  index_predicate_.LateBindValues(index_.get(), *values);

  for (auto &child_plan : GetChildren()) {
    child_plan->SetParameterValues(values);
  }
}

}  // namespace planner
}  // namespace peloton
<commit_msg>Add the logic to set the flag when constructing then IndexScanPlan.<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// index_scan_plan.cpp
//
// Identification: src/planner/index_scan_plan.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "planner/index_scan_plan.h"
#include "expression/constant_value_expression.h"
#include "expression/expression_util.h"
#include "storage/data_table.h"
#include "type/types.h"

namespace peloton {
namespace planner {

IndexScanPlan::IndexScanPlan(storage::DataTable *table,
                             expression::AbstractExpression *predicate,
                             const std::vector<oid_t> &column_ids,
                             const IndexScanDesc &index_scan_desc,
                             bool for_update_flag)
    : index_(index_scan_desc.index_obj),
      column_ids_(column_ids),
      key_column_ids_(std::move(index_scan_desc.tuple_column_id_list)),
      expr_types_(std::move(index_scan_desc.expr_list)),
      values_with_params_(std::move(index_scan_desc.value_list)),
      runtime_keys_(std::move(index_scan_desc.runtime_key_list)),
      // Initialize the index scan predicate object and initialize all
      // keys that we could initialize
      index_predicate_() {
  LOG_TRACE("Creating an Index Scan Plan");

  if (for_update_flag == true) {
    SetForUpdateFlag(true);
  }

  SetTargetTable(table);

  if (predicate != NULL) {
    // we need to copy it here because eventually predicate will be destroyed by
    // its owner...
    predicate = predicate->Copy();
    expression::ExpressionUtil::TransformExpression(table->GetSchema(),
                                                    predicate);
    SetPredicate(predicate);
  }

  // copy the value over for binding purpose
  for (auto val : values_with_params_) {
    values_.push_back(val.Copy());
  }

  // Then add the only conjunction predicate into the index predicate list
  // (at least for now we only supports single conjunction)
  index_predicate_.AddConjunctionScanPredicate(index_.get(), values_,
                                               key_column_ids_, expr_types_);

  // Check whether the scan range is left/right open. Because the index itself
  // is not able to handle that exactly, we must have extra logic in
  // IndexScanExecutor to handle that case.
  //
  // TODO: We may also need a flag for "IN" expression after we support "IN".
  for (auto expr_type : expr_types_) {
    if (expr_type == EXPRESSION_TYPE_COMPARE_GREATERTHAN) left_open_ = true;

    if (expr_type == EXPRESSION_TYPE_COMPARE_LESSTHAN) right_open_ = true;
  }

  return;
}

void IndexScanPlan::SetParameterValues(std::vector<type::Value> *values) {
  LOG_TRACE("Setting parameter values in Index Scans");

  // Destroy the values of the last plan and copy the original values over for
  // binding
  values_.clear();
  for (auto val : values_with_params_) {
    values_.push_back(val.Copy());
  }

  for (unsigned int i = 0; i < values_.size(); ++i) {
    auto value = values_[i];
    auto column_id = key_column_ids_[i];
    if (value.GetTypeId() == type::Type::PARAMETER_OFFSET) {
      int offset = value.GetAs<int32_t>();
      values_[i] =
          (values->at(offset))
              .CastAs(GetTable()->GetSchema()->GetColumn(column_id).GetType());
    }
  }

  // Also bind values to index scan predicate object
  //
  // NOTE: This could only be called by one thread at a time
  index_predicate_.LateBindValues(index_.get(), *values);

  for (auto &child_plan : GetChildren()) {
    child_plan->SetParameterValues(values);
  }
}

}  // namespace planner
}  // namespace peloton
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "stashdialog.h"
#include "gitclient.h"
#include "gitplugin.h"
#include "gitutils.h"
#include "ui_stashdialog.h"

#include <utils/qtcassert.h>

#include <QDebug>
#include <QDir>
#include <QModelIndex>
#include <QDateTime>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
#include <QMessageBox>
#include <QPushButton>

enum { NameColumn, BranchColumn, MessageColumn, ColumnCount };

namespace Git {
namespace Internal {

static inline GitClient *gitClient()
{
    return GitPlugin::instance()->gitClient();
}

static inline QList<QStandardItem*> stashModelRowItems(const Stash &s)
{
    Qt::ItemFlags itemFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    QStandardItem *nameItem = new QStandardItem(s.name);
    nameItem->setFlags(itemFlags);
    QStandardItem *branchItem = new QStandardItem(s.branch);
    branchItem->setFlags(itemFlags);
    QStandardItem *messageItem = new QStandardItem(s.message);
    messageItem->setFlags(itemFlags);
    QList<QStandardItem*> rc;
    rc << nameItem << branchItem << messageItem;
    return rc;
}

// -----------  StashModel
class StashModel : public QStandardItemModel {
public:
    explicit StashModel(QObject *parent = 0);

    void setStashes(const QList<Stash> &stashes);
    const Stash &at(int i) { return m_stashes.at(i); }

private:
    QList<Stash> m_stashes;
};

StashModel::StashModel(QObject *parent) :
    QStandardItemModel(0, ColumnCount, parent)
{
    QStringList headers;
    headers << StashDialog::tr("Name") << StashDialog::tr("Branch") << StashDialog::tr("Message");
    setHorizontalHeaderLabels(headers);
}

void StashModel::setStashes(const QList<Stash> &stashes)
{
    m_stashes = stashes;
    if (const int rows = rowCount())
        removeRows(0, rows);
    foreach (const Stash &s, stashes)
        appendRow(stashModelRowItems(s));
}

// ---------- StashDialog
StashDialog::StashDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::StashDialog),
    m_model(new StashModel),
    m_proxyModel(new QSortFilterProxyModel),
    m_deleteAllButton(new QPushButton(tr("Delete &All..."))),
    m_deleteSelectionButton(new QPushButton(tr("&Delete..."))),
    m_showCurrentButton(new QPushButton(tr("&Show"))),
    m_restoreCurrentButton(new QPushButton(tr("R&estore..."))),
    //: Restore a git stash to new branch to be created
    m_restoreCurrentInBranchButton(new QPushButton(tr("Restore to &Branch..."))),
    m_refreshButton(new QPushButton(tr("Re&fresh")))
{
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
    setAttribute(Qt::WA_DeleteOnClose, true);  // Do not update unnecessarily

    ui->setupUi(this);
    // Buttons
    ui->buttonBox->addButton(m_showCurrentButton, QDialogButtonBox::ActionRole);
    connect(m_showCurrentButton, SIGNAL(clicked()), this, SLOT(showCurrent()));
    ui->buttonBox->addButton(m_refreshButton, QDialogButtonBox::ActionRole);
    connect(m_refreshButton, SIGNAL(clicked()), this, SLOT(forceRefresh()));
    ui->buttonBox->addButton(m_restoreCurrentButton, QDialogButtonBox::ActionRole);
    connect(m_restoreCurrentButton, SIGNAL(clicked()), this, SLOT(restoreCurrent()));
    ui->buttonBox->addButton(m_restoreCurrentInBranchButton, QDialogButtonBox::ActionRole);
    connect(m_restoreCurrentInBranchButton, SIGNAL(clicked()), this, SLOT(restoreCurrentInBranch()));
    ui->buttonBox->addButton(m_deleteSelectionButton, QDialogButtonBox::ActionRole);
    connect(m_deleteSelectionButton, SIGNAL(clicked()), this, SLOT(deleteSelection()));
    ui->buttonBox->addButton(m_deleteAllButton, QDialogButtonBox::ActionRole);
    connect(m_deleteAllButton, SIGNAL(clicked()), this, SLOT(deleteAll()));
    // Models
    m_proxyModel->setSourceModel(m_model);
    m_proxyModel->setFilterKeyColumn(-1);
    m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    ui->stashView->setModel(m_proxyModel);
    ui->stashView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    ui->stashView->setAllColumnsShowFocus(true);
    ui->stashView->setUniformRowHeights(true);
    connect(ui->filterLineEdit, SIGNAL(filterChanged(QString)), m_proxyModel, SLOT(setFilterFixedString(QString)));
    connect(ui->stashView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
            this, SLOT(enableButtons()));
    connect(ui->stashView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
            this, SLOT(enableButtons()));
    connect(ui->stashView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(showCurrent()));
    ui->stashView->setFocus();
}

StashDialog::~StashDialog()
{
    delete ui;
}

QString StashDialog::msgRepositoryLabel(const QString &repository)
{
    return repository.isEmpty() ?
            tr("<No repository>")  :
            tr("Repository: %1").arg(QDir::toNativeSeparators(repository));
}

void StashDialog::refresh(const QString &repository, bool force)
{
    if (m_repository == repository && !force)
        return;
    // Refresh
    m_repository = repository;
    ui->repositoryLabel->setText(msgRepositoryLabel(repository));
    if (m_repository.isEmpty()) {
        m_model->setStashes(QList<Stash>());
    } else {
        QList<Stash> stashes;
        gitClient()->synchronousStashList(m_repository, &stashes);
        m_model->setStashes(stashes);
        if (!stashes.isEmpty()) {
            for (int c = 0; c < ColumnCount; c++)
                ui->stashView->resizeColumnToContents(c);
        }
    }
    enableButtons();
}

void StashDialog::deleteAll()
{
    const QString title = tr("Delete Stashes");
    if (!ask(title, tr("Do you want to delete all stashes?")))
        return;
    QString errorMessage;
    if (gitClient()->synchronousStashRemove(m_repository, QString(), &errorMessage))
        refresh(m_repository, true);
    else
        warning(title, errorMessage);
}

void StashDialog::deleteSelection()
{
    const QList<int> rows = selectedRows();
    QTC_ASSERT(!rows.isEmpty(), return);
    const QString title = tr("Delete Stashes");
    if (!ask(title, tr("Do you want to delete %n stash(es)?", 0, rows.size())))
        return;
    QString errorMessage;
    QStringList errors;
    // Delete in reverse order as stashes rotate
    for (int r = rows.size() - 1; r >= 0; r--)
        if (!gitClient()->synchronousStashRemove(m_repository, m_model->at(rows.at(r)).name, &errorMessage))
            errors.push_back(errorMessage);
    refresh(m_repository, true);
    if (!errors.isEmpty())
        warning(title, errors.join(QString(QLatin1Char('\n'))));
}

void StashDialog::showCurrent()
{
    const int index = currentRow();
    QTC_ASSERT(index >= 0, return);
    gitClient()->show(m_repository, m_model->at(index).name);
}

// Suggest Branch name to restore 'stash@{0}' -> 'stash0-date'
static inline QString stashRestoreDefaultBranch(QString stash)
{
    stash.remove(QLatin1Char('{'));
    stash.remove(QLatin1Char('}'));
    stash.remove(QLatin1Char('@'));
    stash += QLatin1Char('-');
    stash += QDateTime::currentDateTime().toString(QLatin1String("yyMMddhhmmss"));
    return stash;
}

// Return next stash id 'stash@{0}' -> 'stash@{1}'
static inline QString nextStash(const QString &stash)
{
    const int openingBracePos = stash.indexOf(QLatin1Char('{'));
    if (openingBracePos == -1)
        return QString();
    const int closingBracePos = stash.indexOf(QLatin1Char('}'), openingBracePos + 2);
    if (closingBracePos == -1)
        return QString();
    bool ok;
    const int n = stash.mid(openingBracePos + 1, closingBracePos - openingBracePos - 1).toInt(&ok);
    if (!ok)
        return QString();
    QString rc =  stash.left(openingBracePos + 1);
    rc += QString::number(n + 1);
    rc += QLatin1Char('}');
    return rc;
}

StashDialog::ModifiedRepositoryAction StashDialog::promptModifiedRepository(const QString &stash)
{
    QMessageBox box(QMessageBox::Question,
                    tr("Repository Modified"),
                    tr("%1 cannot be restored since the repository is modified.\n"
                       "You can choose between stashing the changes or discarding them.").arg(stash),
                    QMessageBox::Cancel, this);
    QPushButton *stashButton = box.addButton(tr("Stash"), QMessageBox::AcceptRole);
    QPushButton *discardButton = box.addButton(tr("Discard"), QMessageBox::AcceptRole);
    box.exec();
    const QAbstractButton *clickedButton = box.clickedButton();
    if (clickedButton == stashButton)
        return ModifiedRepositoryStash;
    if (clickedButton == discardButton)
        return ModifiedRepositoryDiscard;
    return ModifiedRepositoryCancel;
}

// Prompt for restore: Make sure repository is unmodified,
// prompt for a branch if desired or just ask to restore.
// Note that the stash to be restored changes if the user
// chooses to stash away modified repository.
bool StashDialog::promptForRestore(QString *stash,
                                   QString *branch /* = 0*/,
                                   QString *errorMessage)
{
    const QString stashIn = *stash;
    bool modifiedPromptShown = false;
    switch (gitClient()->gitStatus(m_repository, StatusMode(NoUntracked | NoSubmodules), 0, errorMessage)) {
    case GitClient::StatusFailed:
        return false;
    case GitClient::StatusChanged: {
            switch (promptModifiedRepository(*stash)) {
            case ModifiedRepositoryCancel:
                return false;
            case ModifiedRepositoryStash:
                if (gitClient()->synchronousStash(m_repository, QString(), GitClient::StashPromptDescription).isEmpty())
                    return false;
                *stash = nextStash(*stash); // Our stash id to be restored changed
                QTC_ASSERT(!stash->isEmpty(), return false);
                break;
            case ModifiedRepositoryDiscard:
                if (!gitClient()->synchronousReset(m_repository))
                    return false;
                break;
            }
        modifiedPromptShown = true;
    }
        break;
    case GitClient::StatusUnchanged:
        break;
    }
    // Prompt for branch or just ask.
    if (branch) {
        *branch = stashRestoreDefaultBranch(*stash);
        if (!inputText(this, tr("Restore Stash to Branch"), tr("Branch:"), branch)
            || branch->isEmpty())
            return false;
    } else {
        if (!modifiedPromptShown && !ask(tr("Stash Restore"), tr("Would you like to restore %1?").arg(stashIn)))
            return false;
    }
    return true;
}

static inline QString msgRestoreFailedTitle(const QString &stash)
{
    return StashDialog::tr("Error restoring %1").arg(stash);
}

void StashDialog::restoreCurrent()
{
    const int index = currentRow();
    QTC_ASSERT(index >= 0, return);
    QString errorMessage;
    QString name = m_model->at(index).name;
    // Make sure repository is not modified, restore. The command will
    // output to window on success.
    const bool success = promptForRestore(&name, 0, &errorMessage)
                         && gitClient()->synchronousStashRestore(m_repository, name, false, QString(), &errorMessage);
    if (success) {
        refresh(m_repository, true); // Might have stashed away local changes.
    } else {
        if (!errorMessage.isEmpty())
        warning(msgRestoreFailedTitle(name), errorMessage);
    }
}

void StashDialog::restoreCurrentInBranch()
{
    const int index = currentRow();
    QTC_ASSERT(index >= 0, return);
    QString errorMessage;
    QString branch;
    QString name = m_model->at(index).name;
    const bool success = promptForRestore(&name, &branch, &errorMessage)
                         && gitClient()->synchronousStashRestore(m_repository, name, false, branch, &errorMessage);
    if (success) {
        refresh(m_repository, true); // git deletes the stash, unfortunately.
    } else {
        if (!errorMessage.isEmpty())
            warning(msgRestoreFailedTitle(name), errorMessage);
    }
}

int StashDialog::currentRow() const
{
    const QModelIndex proxyIndex = ui->stashView->currentIndex();
    if (proxyIndex.isValid()) {
        const QModelIndex index = m_proxyModel->mapToSource(proxyIndex);
        if (index.isValid())
            return index.row();
    }
    return -1;
}

QList<int> StashDialog::selectedRows() const
{
    QList<int> rc;
    foreach (const QModelIndex &proxyIndex, ui->stashView->selectionModel()->selectedRows()) {
        const QModelIndex index = m_proxyModel->mapToSource(proxyIndex);
        if (index.isValid())
            rc.push_back(index.row());
    }
    qSort(rc);
    return rc;
}

void StashDialog::forceRefresh()
{
    refresh(m_repository, true);
}

void StashDialog::enableButtons()
{
    const bool hasRepository = !m_repository.isEmpty();
    const bool hasStashes = hasRepository && m_model->rowCount();
    const bool hasCurrentRow = hasRepository && hasStashes && currentRow() >= 0;
    m_deleteAllButton->setEnabled(hasStashes);
    m_showCurrentButton->setEnabled(hasCurrentRow);
    m_restoreCurrentButton->setEnabled(hasCurrentRow);
    m_restoreCurrentInBranchButton->setEnabled(hasCurrentRow);
    const bool hasSelection = !ui->stashView->selectionModel()->selectedRows().isEmpty();
    m_deleteSelectionButton->setEnabled(hasSelection);
    m_refreshButton->setEnabled(hasRepository);
}

void StashDialog::warning(const QString &title, const QString &what, const QString &details)
{
    QMessageBox msgBox(QMessageBox::Warning, title, what, QMessageBox::Ok, this);
    if (!details.isEmpty())
        msgBox.setDetailedText(details);
    msgBox.exec();
}

bool StashDialog::ask(const QString &title, const QString &what, bool defaultButton)
{
    return QMessageBox::question(
                this, title, what, QMessageBox::Yes | QMessageBox::No,
                defaultButton ? QMessageBox::Yes : QMessageBox::No) == QMessageBox::Yes;
}

} // namespace Internal
} // namespace Git
<commit_msg>Git: Fix crash on show stash<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "stashdialog.h"
#include "gitclient.h"
#include "gitplugin.h"
#include "gitutils.h"
#include "ui_stashdialog.h"

#include <utils/qtcassert.h>

#include <QDebug>
#include <QDir>
#include <QModelIndex>
#include <QDateTime>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
#include <QMessageBox>
#include <QPushButton>

enum { NameColumn, BranchColumn, MessageColumn, ColumnCount };

namespace Git {
namespace Internal {

static inline GitClient *gitClient()
{
    return GitPlugin::instance()->gitClient();
}

static inline QList<QStandardItem*> stashModelRowItems(const Stash &s)
{
    Qt::ItemFlags itemFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    QStandardItem *nameItem = new QStandardItem(s.name);
    nameItem->setFlags(itemFlags);
    QStandardItem *branchItem = new QStandardItem(s.branch);
    branchItem->setFlags(itemFlags);
    QStandardItem *messageItem = new QStandardItem(s.message);
    messageItem->setFlags(itemFlags);
    QList<QStandardItem*> rc;
    rc << nameItem << branchItem << messageItem;
    return rc;
}

// -----------  StashModel
class StashModel : public QStandardItemModel {
public:
    explicit StashModel(QObject *parent = 0);

    void setStashes(const QList<Stash> &stashes);
    const Stash &at(int i) { return m_stashes.at(i); }

private:
    QList<Stash> m_stashes;
};

StashModel::StashModel(QObject *parent) :
    QStandardItemModel(0, ColumnCount, parent)
{
    QStringList headers;
    headers << StashDialog::tr("Name") << StashDialog::tr("Branch") << StashDialog::tr("Message");
    setHorizontalHeaderLabels(headers);
}

void StashModel::setStashes(const QList<Stash> &stashes)
{
    m_stashes = stashes;
    if (const int rows = rowCount())
        removeRows(0, rows);
    foreach (const Stash &s, stashes)
        appendRow(stashModelRowItems(s));
}

// ---------- StashDialog
StashDialog::StashDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::StashDialog),
    m_model(new StashModel),
    m_proxyModel(new QSortFilterProxyModel),
    m_deleteAllButton(new QPushButton(tr("Delete &All..."))),
    m_deleteSelectionButton(new QPushButton(tr("&Delete..."))),
    m_showCurrentButton(new QPushButton(tr("&Show"))),
    m_restoreCurrentButton(new QPushButton(tr("R&estore..."))),
    //: Restore a git stash to new branch to be created
    m_restoreCurrentInBranchButton(new QPushButton(tr("Restore to &Branch..."))),
    m_refreshButton(new QPushButton(tr("Re&fresh")))
{
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
    setAttribute(Qt::WA_DeleteOnClose, true);  // Do not update unnecessarily

    ui->setupUi(this);
    // Buttons
    ui->buttonBox->addButton(m_showCurrentButton, QDialogButtonBox::ActionRole);
    connect(m_showCurrentButton, SIGNAL(clicked()), this, SLOT(showCurrent()));
    ui->buttonBox->addButton(m_refreshButton, QDialogButtonBox::ActionRole);
    connect(m_refreshButton, SIGNAL(clicked()), this, SLOT(forceRefresh()));
    ui->buttonBox->addButton(m_restoreCurrentButton, QDialogButtonBox::ActionRole);
    connect(m_restoreCurrentButton, SIGNAL(clicked()), this, SLOT(restoreCurrent()));
    ui->buttonBox->addButton(m_restoreCurrentInBranchButton, QDialogButtonBox::ActionRole);
    connect(m_restoreCurrentInBranchButton, SIGNAL(clicked()), this, SLOT(restoreCurrentInBranch()));
    ui->buttonBox->addButton(m_deleteSelectionButton, QDialogButtonBox::ActionRole);
    connect(m_deleteSelectionButton, SIGNAL(clicked()), this, SLOT(deleteSelection()));
    ui->buttonBox->addButton(m_deleteAllButton, QDialogButtonBox::ActionRole);
    connect(m_deleteAllButton, SIGNAL(clicked()), this, SLOT(deleteAll()));
    // Models
    m_proxyModel->setSourceModel(m_model);
    m_proxyModel->setFilterKeyColumn(-1);
    m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    ui->stashView->setModel(m_proxyModel);
    ui->stashView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    ui->stashView->setAllColumnsShowFocus(true);
    ui->stashView->setUniformRowHeights(true);
    connect(ui->filterLineEdit, SIGNAL(filterChanged(QString)), m_proxyModel, SLOT(setFilterFixedString(QString)));
    connect(ui->stashView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
            this, SLOT(enableButtons()));
    connect(ui->stashView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
            this, SLOT(enableButtons()));
    connect(ui->stashView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(showCurrent()));
    ui->stashView->setFocus();
}

StashDialog::~StashDialog()
{
    delete ui;
}

QString StashDialog::msgRepositoryLabel(const QString &repository)
{
    return repository.isEmpty() ?
            tr("<No repository>")  :
            tr("Repository: %1").arg(QDir::toNativeSeparators(repository));
}

void StashDialog::refresh(const QString &repository, bool force)
{
    if (m_repository == repository && !force)
        return;
    // Refresh
    m_repository = repository;
    ui->repositoryLabel->setText(msgRepositoryLabel(repository));
    if (m_repository.isEmpty()) {
        m_model->setStashes(QList<Stash>());
    } else {
        QList<Stash> stashes;
        gitClient()->synchronousStashList(m_repository, &stashes);
        m_model->setStashes(stashes);
        if (!stashes.isEmpty()) {
            for (int c = 0; c < ColumnCount; c++)
                ui->stashView->resizeColumnToContents(c);
        }
    }
    enableButtons();
}

void StashDialog::deleteAll()
{
    const QString title = tr("Delete Stashes");
    if (!ask(title, tr("Do you want to delete all stashes?")))
        return;
    QString errorMessage;
    if (gitClient()->synchronousStashRemove(m_repository, QString(), &errorMessage))
        refresh(m_repository, true);
    else
        warning(title, errorMessage);
}

void StashDialog::deleteSelection()
{
    const QList<int> rows = selectedRows();
    QTC_ASSERT(!rows.isEmpty(), return);
    const QString title = tr("Delete Stashes");
    if (!ask(title, tr("Do you want to delete %n stash(es)?", 0, rows.size())))
        return;
    QString errorMessage;
    QStringList errors;
    // Delete in reverse order as stashes rotate
    for (int r = rows.size() - 1; r >= 0; r--)
        if (!gitClient()->synchronousStashRemove(m_repository, m_model->at(rows.at(r)).name, &errorMessage))
            errors.push_back(errorMessage);
    refresh(m_repository, true);
    if (!errors.isEmpty())
        warning(title, errors.join(QString(QLatin1Char('\n'))));
}

void StashDialog::showCurrent()
{
    const int index = currentRow();
    QTC_ASSERT(index >= 0, return);
    gitClient()->show(m_repository, QString(m_model->at(index).name));
}

// Suggest Branch name to restore 'stash@{0}' -> 'stash0-date'
static inline QString stashRestoreDefaultBranch(QString stash)
{
    stash.remove(QLatin1Char('{'));
    stash.remove(QLatin1Char('}'));
    stash.remove(QLatin1Char('@'));
    stash += QLatin1Char('-');
    stash += QDateTime::currentDateTime().toString(QLatin1String("yyMMddhhmmss"));
    return stash;
}

// Return next stash id 'stash@{0}' -> 'stash@{1}'
static inline QString nextStash(const QString &stash)
{
    const int openingBracePos = stash.indexOf(QLatin1Char('{'));
    if (openingBracePos == -1)
        return QString();
    const int closingBracePos = stash.indexOf(QLatin1Char('}'), openingBracePos + 2);
    if (closingBracePos == -1)
        return QString();
    bool ok;
    const int n = stash.mid(openingBracePos + 1, closingBracePos - openingBracePos - 1).toInt(&ok);
    if (!ok)
        return QString();
    QString rc =  stash.left(openingBracePos + 1);
    rc += QString::number(n + 1);
    rc += QLatin1Char('}');
    return rc;
}

StashDialog::ModifiedRepositoryAction StashDialog::promptModifiedRepository(const QString &stash)
{
    QMessageBox box(QMessageBox::Question,
                    tr("Repository Modified"),
                    tr("%1 cannot be restored since the repository is modified.\n"
                       "You can choose between stashing the changes or discarding them.").arg(stash),
                    QMessageBox::Cancel, this);
    QPushButton *stashButton = box.addButton(tr("Stash"), QMessageBox::AcceptRole);
    QPushButton *discardButton = box.addButton(tr("Discard"), QMessageBox::AcceptRole);
    box.exec();
    const QAbstractButton *clickedButton = box.clickedButton();
    if (clickedButton == stashButton)
        return ModifiedRepositoryStash;
    if (clickedButton == discardButton)
        return ModifiedRepositoryDiscard;
    return ModifiedRepositoryCancel;
}

// Prompt for restore: Make sure repository is unmodified,
// prompt for a branch if desired or just ask to restore.
// Note that the stash to be restored changes if the user
// chooses to stash away modified repository.
bool StashDialog::promptForRestore(QString *stash,
                                   QString *branch /* = 0*/,
                                   QString *errorMessage)
{
    const QString stashIn = *stash;
    bool modifiedPromptShown = false;
    switch (gitClient()->gitStatus(m_repository, StatusMode(NoUntracked | NoSubmodules), 0, errorMessage)) {
    case GitClient::StatusFailed:
        return false;
    case GitClient::StatusChanged: {
            switch (promptModifiedRepository(*stash)) {
            case ModifiedRepositoryCancel:
                return false;
            case ModifiedRepositoryStash:
                if (gitClient()->synchronousStash(m_repository, QString(), GitClient::StashPromptDescription).isEmpty())
                    return false;
                *stash = nextStash(*stash); // Our stash id to be restored changed
                QTC_ASSERT(!stash->isEmpty(), return false);
                break;
            case ModifiedRepositoryDiscard:
                if (!gitClient()->synchronousReset(m_repository))
                    return false;
                break;
            }
        modifiedPromptShown = true;
    }
        break;
    case GitClient::StatusUnchanged:
        break;
    }
    // Prompt for branch or just ask.
    if (branch) {
        *branch = stashRestoreDefaultBranch(*stash);
        if (!inputText(this, tr("Restore Stash to Branch"), tr("Branch:"), branch)
            || branch->isEmpty())
            return false;
    } else {
        if (!modifiedPromptShown && !ask(tr("Stash Restore"), tr("Would you like to restore %1?").arg(stashIn)))
            return false;
    }
    return true;
}

static inline QString msgRestoreFailedTitle(const QString &stash)
{
    return StashDialog::tr("Error restoring %1").arg(stash);
}

void StashDialog::restoreCurrent()
{
    const int index = currentRow();
    QTC_ASSERT(index >= 0, return);
    QString errorMessage;
    QString name = m_model->at(index).name;
    // Make sure repository is not modified, restore. The command will
    // output to window on success.
    const bool success = promptForRestore(&name, 0, &errorMessage)
                         && gitClient()->synchronousStashRestore(m_repository, name, false, QString(), &errorMessage);
    if (success) {
        refresh(m_repository, true); // Might have stashed away local changes.
    } else {
        if (!errorMessage.isEmpty())
        warning(msgRestoreFailedTitle(name), errorMessage);
    }
}

void StashDialog::restoreCurrentInBranch()
{
    const int index = currentRow();
    QTC_ASSERT(index >= 0, return);
    QString errorMessage;
    QString branch;
    QString name = m_model->at(index).name;
    const bool success = promptForRestore(&name, &branch, &errorMessage)
                         && gitClient()->synchronousStashRestore(m_repository, name, false, branch, &errorMessage);
    if (success) {
        refresh(m_repository, true); // git deletes the stash, unfortunately.
    } else {
        if (!errorMessage.isEmpty())
            warning(msgRestoreFailedTitle(name), errorMessage);
    }
}

int StashDialog::currentRow() const
{
    const QModelIndex proxyIndex = ui->stashView->currentIndex();
    if (proxyIndex.isValid()) {
        const QModelIndex index = m_proxyModel->mapToSource(proxyIndex);
        if (index.isValid())
            return index.row();
    }
    return -1;
}

QList<int> StashDialog::selectedRows() const
{
    QList<int> rc;
    foreach (const QModelIndex &proxyIndex, ui->stashView->selectionModel()->selectedRows()) {
        const QModelIndex index = m_proxyModel->mapToSource(proxyIndex);
        if (index.isValid())
            rc.push_back(index.row());
    }
    qSort(rc);
    return rc;
}

void StashDialog::forceRefresh()
{
    refresh(m_repository, true);
}

void StashDialog::enableButtons()
{
    const bool hasRepository = !m_repository.isEmpty();
    const bool hasStashes = hasRepository && m_model->rowCount();
    const bool hasCurrentRow = hasRepository && hasStashes && currentRow() >= 0;
    m_deleteAllButton->setEnabled(hasStashes);
    m_showCurrentButton->setEnabled(hasCurrentRow);
    m_restoreCurrentButton->setEnabled(hasCurrentRow);
    m_restoreCurrentInBranchButton->setEnabled(hasCurrentRow);
    const bool hasSelection = !ui->stashView->selectionModel()->selectedRows().isEmpty();
    m_deleteSelectionButton->setEnabled(hasSelection);
    m_refreshButton->setEnabled(hasRepository);
}

void StashDialog::warning(const QString &title, const QString &what, const QString &details)
{
    QMessageBox msgBox(QMessageBox::Warning, title, what, QMessageBox::Ok, this);
    if (!details.isEmpty())
        msgBox.setDetailedText(details);
    msgBox.exec();
}

bool StashDialog::ask(const QString &title, const QString &what, bool defaultButton)
{
    return QMessageBox::question(
                this, title, what, QMessageBox::Yes | QMessageBox::No,
                defaultButton ? QMessageBox::Yes : QMessageBox::No) == QMessageBox::Yes;
}

} // namespace Internal
} // namespace Git
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include <QtTest>
#include <QDebug>

#include <Token.h>
#include <SimpleLexer.h>

Q_DECLARE_METATYPE(QList<unsigned>)

//TESTED_COMPONENT=src/libs/cplusplus
using namespace CPlusPlus;

class tst_SimpleLexer: public QObject
{
    Q_OBJECT

private slots:
    void doxygen_comments();
    void doxygen_comments_data();
};

void tst_SimpleLexer::doxygen_comments()
{
    QFETCH(QByteArray, source);
    QFETCH(QList<unsigned>, expectedTokenKindList);

    SimpleLexer lexer;
    const QList<Token> tokenList = lexer(source);

    int i = 0;
    for (; i < tokenList.size(); ++i) {
        QVERIFY2(i < expectedTokenKindList.size(), "More tokens than expected.");

        // Compare spelled tokens to have it more readable
        const Token token = tokenList.at(i);
        const unsigned expectedTokenKind = expectedTokenKindList.at(i);
        Token expectedToken; // Create a Token in order to spell the token kind
        expectedToken.f.kind = expectedTokenKind;
//        qDebug("Comparing (i=%d): \"%s\" \"%s\"", i, token.spell(), expectedToken.spell());
        QCOMPARE(token.kind(), expectedTokenKind);
    }
    QVERIFY2(i == expectedTokenKindList.size(), "Less tokens than expected.");
}

void tst_SimpleLexer::doxygen_comments_data()
{
    QTest::addColumn<QByteArray>("source");
    QTest::addColumn<QList<unsigned> >("expectedTokenKindList");

    QByteArray source;
    QList<unsigned> expectedTokenKindList;

    source = "// comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "//// comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "/// comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "///< comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "//! comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "//!< comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "///\n";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "///\n"
             "int i;";
    expectedTokenKindList = QList<unsigned>()
        << T_CPP_DOXY_COMMENT
        << T_INT << T_IDENTIFIER << T_SEMICOLON;
    QTest::newRow(source) << source << expectedTokenKindList;
}

QTEST_APPLESS_MAIN(tst_SimpleLexer)
#include "tst_lexer.moc"
<commit_msg>C++: Tests: More lexer tests for doxygen comments<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include <QtTest>
#include <QDebug>

#include <Token.h>
#include <SimpleLexer.h>

Q_DECLARE_METATYPE(QList<unsigned>)

//TESTED_COMPONENT=src/libs/cplusplus
using namespace CPlusPlus;

class tst_SimpleLexer: public QObject
{
    Q_OBJECT

private slots:
    void doxygen_comments();
    void doxygen_comments_data();
};

void tst_SimpleLexer::doxygen_comments()
{
    QFETCH(QByteArray, source);
    QFETCH(QList<unsigned>, expectedTokenKindList);

    SimpleLexer lexer;
    const QList<Token> tokenList = lexer(source);

    int i = 0;
    for (; i < tokenList.size(); ++i) {
        QVERIFY2(i < expectedTokenKindList.size(), "More tokens than expected.");

        // Compare spelled tokens to have it more readable
        const Token token = tokenList.at(i);
        const unsigned expectedTokenKind = expectedTokenKindList.at(i);
        Token expectedToken; // Create a Token in order to spell the token kind
        expectedToken.f.kind = expectedTokenKind;
//        qDebug("Comparing (i=%d): \"%s\" \"%s\"", i, token.spell(), expectedToken.spell());
        QCOMPARE(token.kind(), expectedTokenKind);
    }
    QVERIFY2(i == expectedTokenKindList.size(), "Less tokens than expected.");
}

void tst_SimpleLexer::doxygen_comments_data()
{
    QTest::addColumn<QByteArray>("source");
    QTest::addColumn<QList<unsigned> >("expectedTokenKindList");

    QByteArray source;
    QList<unsigned> expectedTokenKindList;

    source = "// comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "//// comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "/// comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "///< comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "//! comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "//!< comment";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "///\n";
    expectedTokenKindList = QList<unsigned>() << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "///\n"
             "int i;";
    expectedTokenKindList = QList<unsigned>()
        << T_CPP_DOXY_COMMENT
        << T_INT << T_IDENTIFIER << T_SEMICOLON;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "/* comment */\n";
    expectedTokenKindList = QList<unsigned>() << T_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "/* comment\n"
             "   comment\n"
             " */\n";
    expectedTokenKindList = QList<unsigned>() << T_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "/** comment */";
    expectedTokenKindList = QList<unsigned>() << T_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "/** comment */\n";
    expectedTokenKindList = QList<unsigned>() << T_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "/** comment */ int i;\n";
    expectedTokenKindList = QList<unsigned>()
        << T_DOXY_COMMENT << T_INT << T_IDENTIFIER << T_SEMICOLON;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "/**\n"
            "  * comment\n"
             " */\n";
    expectedTokenKindList = QList<unsigned>() << T_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "/*!\n"
            "  * comment\n"
             " */\n";
    expectedTokenKindList = QList<unsigned>() << T_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "/*!\n"
             "    comment\n"
             "*/\n";
    expectedTokenKindList = QList<unsigned>() << T_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;

    source = "int i; /*!< first counter */\n"
             "int j; /**< second counter */\n"
             "int k; ///< third counter\n"
             "int l; //!< fourth counter\n"
             "       //!< more details...  ";
    expectedTokenKindList = QList<unsigned>()
        << T_INT << T_IDENTIFIER << T_SEMICOLON << T_DOXY_COMMENT
        << T_INT << T_IDENTIFIER << T_SEMICOLON << T_DOXY_COMMENT
        << T_INT << T_IDENTIFIER << T_SEMICOLON << T_CPP_DOXY_COMMENT
        << T_INT << T_IDENTIFIER << T_SEMICOLON << T_CPP_DOXY_COMMENT << T_CPP_DOXY_COMMENT;
    QTest::newRow(source) << source << expectedTokenKindList;
}

QTEST_APPLESS_MAIN(tst_SimpleLexer)
#include "tst_lexer.moc"
<|endoftext|>


<commit_before>

#include "config.h"
#include "storage/StorageImpl.h"
#include "storage/DevicegraphImpl.h"
#include "storage/Devices/DiskImpl.h"
#include "storage/Devices/FilesystemImpl.h"
#include "storage/SystemInfo/SystemInfo.h"
#include "storage/Actiongraph.h"
#include "storage/Utils/AppUtil.h"
#include "storage/Utils/Mockup.h"

namespace storage
{

    Storage::Impl::Impl(const Storage& storage, const Environment& environment)
	: storage(storage), environment(environment), arch(false)
    {
	y2mil("constructed Storage with " << environment);
	y2mil("libstorage version " VERSION);

	Devicegraph* probed = create_devicegraph("probed");

	switch (environment.get_probe_mode())
	{
	    case ProbeMode::STANDARD: {
		probe(probed);
	    } break;

	    case ProbeMode::STANDARD_WRITE_DEVICEGRAPH: {
		probe(probed);
		probed->save(environment.get_devicegraph_filename());
	    } break;

	    case ProbeMode::STANDARD_WRITE_MOCKUP: {
		Mockup::set_mode(Mockup::Mode::RECORD);
		probe(probed);
		Mockup::save(environment.get_mockup_filename());
	    } break;

	    case ProbeMode::NONE: {
	    } break;

	    case ProbeMode::READ_DEVICEGRAPH: {
		probed->load(environment.get_devicegraph_filename());
	    } break;

	    case ProbeMode::READ_MOCKUP: {
		Mockup::set_mode(Mockup::Mode::PLAYBACK);
		Mockup::load(environment.get_mockup_filename());
		probe(probed);
	    } break;
	}

	y2mil("probed devicegraph begin");
	y2mil(*probed);
	y2mil("probed devicegraph end");

	copy_devicegraph("probed", "staging");
    }

    Storage::Impl::~Impl()
    {
	y2mil("destructed Storage");
    }

    void
    Storage::Impl::probe(Devicegraph* probed)
    {
	SystemInfo systeminfo;

	arch = systeminfo.getArch();

	EtcFstab fstab("/etc");

	// TODO

	for (const string& name : Disk::Impl::probe_disks(systeminfo))
	{
	    Disk* disk = Disk::create(probed, name);
	    disk->get_impl().probe(systeminfo);
	}

	for (Devicegraph::Impl::vertex_descriptor vertex : probed->get_impl().vertices())
	{
	    BlkDevice* blkdevice = dynamic_cast<BlkDevice*>(probed->get_impl()[vertex]);
	    if (!blkdevice)
		continue;

	    if (blkdevice->num_children() != 0)
		continue;

	    Blkid::Entry entry;
	    if (systeminfo.getBlkid().getEntry(blkdevice->get_name(), entry))
	    {
		if (entry.is_fs)
		{
		    // TODO temporary until all fs are implemented
		    if (entry.fs_type != EXT4 && entry.fs_type != BTRFS && entry.fs_type != XFS &&
			entry.fs_type != SWAP)
			continue;

		    Filesystem* filesystem = blkdevice->create_filesystem(entry.fs_type);
		    filesystem->get_impl().probe(systeminfo, fstab);
		}
	    }
	}
    }

    Devicegraph*
    Storage::Impl::get_devicegraph(const string& name)
    {
	if (name == "probed")
	    throw runtime_error("invalid name");

	map<string, Devicegraph>::iterator it = devicegraphs.find(name);
	if (it == devicegraphs.end())
	    throw runtime_error("device graph not found");

	return &it->second;
    }

    const Devicegraph*
    Storage::Impl::get_devicegraph(const string& name) const
    {
	map<string, Devicegraph>::const_iterator it = devicegraphs.find(name);
	if (it == devicegraphs.end())
	    throw runtime_error("device graph not found");

	return &it->second;
    }

    Devicegraph*
    Storage::Impl::get_staging()
    {
	return get_devicegraph("staging");
    }

    const Devicegraph*
    Storage::Impl::get_staging() const
    {
	return get_devicegraph("staging");
    }

    const Devicegraph*
    Storage::Impl::get_probed() const
    {
	return get_devicegraph("probed");
    }

    vector<string>
    Storage::Impl::get_devicegraph_names() const
    {
	vector<string> ret;

	for (const map<string, Devicegraph>::value_type& it : devicegraphs)
	    ret.push_back(it.first);

	return ret;
    }

    Devicegraph*
    Storage::Impl::create_devicegraph(const string& name)
    {
	pair<map<string, Devicegraph>::iterator, bool> tmp =
	    devicegraphs.emplace(piecewise_construct, forward_as_tuple(name),
				 forward_as_tuple(&storage));
	if (!tmp.second)
	    throw logic_error("device graph already exists");

	map<string, Devicegraph>::iterator it = tmp.first;

	return &it->second;
    }

    Devicegraph*
    Storage::Impl::copy_devicegraph(const string& source_name, const string& dest_name)
    {
	const Devicegraph* tmp1 = static_cast<const Impl*>(this)->get_devicegraph(source_name);

	Devicegraph* tmp2 = create_devicegraph(dest_name);

	tmp1->copy(*tmp2);

	return tmp2;
    }

    void
    Storage::Impl::remove_devicegraph(const string& name)
    {
	map<string, Devicegraph>::const_iterator it1 = devicegraphs.find(name);
	if (it1 == devicegraphs.end())
	    throw runtime_error("device graph not found");

	devicegraphs.erase(it1);
    }

    void
    Storage::Impl::restore_devicegraph(const string& name)
    {
	map<string, Devicegraph>::iterator it1 = devicegraphs.find(name);
	if (it1 == devicegraphs.end())
	    throw runtime_error("device graph not found");

	map<string, Devicegraph>::iterator it2 = devicegraphs.find("staging");
	if (it2 == devicegraphs.end())
	    throw runtime_error("device graph not found");

	it1->second.get_impl().swap(it2->second.get_impl());
	devicegraphs.erase(it1);
    }

    bool
    Storage::Impl::exist_devicegraph(const string& name) const
    {
	return devicegraphs.find(name) != devicegraphs.end();
    }

    bool
    Storage::Impl::equal_devicegraph(const string& lhs, const string& rhs) const
    {
	return *get_devicegraph(lhs) == *get_devicegraph(rhs);
    }

    void
    Storage::Impl::check() const
    {
	for (const map<string, Devicegraph>::value_type& key_value : devicegraphs)
	{
	    key_value.second.check();
	}

	// TODO check that a object has the same type in every devicegraph
    }

    string
    Storage::Impl::prepend_rootprefix(const string& mountpoint) const
    {
	if (mountpoint == "swap" || rootprefix.empty())
	    return mountpoint;

	if (mountpoint == "/")
	    return rootprefix;
	else
	    return rootprefix + mountpoint;
    }

    const Actiongraph*
    Storage::Impl::calculate_actiongraph()
    {
	actiongraph.reset(new Actiongraph(storage, get_probed(), get_staging()));

	return actiongraph.get();
    }

    void
    Storage::Impl::commit(const CommitCallbacks* commit_callbacks)
    {
	actiongraph->get_impl().commit(commit_callbacks);

	// TODO somehow update probed
    }

}
<commit_msg>- added check<commit_after>

#include "config.h"
#include "storage/StorageImpl.h"
#include "storage/DevicegraphImpl.h"
#include "storage/Devices/DiskImpl.h"
#include "storage/Devices/FilesystemImpl.h"
#include "storage/SystemInfo/SystemInfo.h"
#include "storage/Actiongraph.h"
#include "storage/Utils/AppUtil.h"
#include "storage/Utils/Mockup.h"

namespace storage
{

    Storage::Impl::Impl(const Storage& storage, const Environment& environment)
	: storage(storage), environment(environment), arch(false)
    {
	y2mil("constructed Storage with " << environment);
	y2mil("libstorage version " VERSION);

	Devicegraph* probed = create_devicegraph("probed");

	switch (environment.get_probe_mode())
	{
	    case ProbeMode::STANDARD: {
		probe(probed);
	    } break;

	    case ProbeMode::STANDARD_WRITE_DEVICEGRAPH: {
		probe(probed);
		probed->save(environment.get_devicegraph_filename());
	    } break;

	    case ProbeMode::STANDARD_WRITE_MOCKUP: {
		Mockup::set_mode(Mockup::Mode::RECORD);
		probe(probed);
		Mockup::save(environment.get_mockup_filename());
	    } break;

	    case ProbeMode::NONE: {
	    } break;

	    case ProbeMode::READ_DEVICEGRAPH: {
		probed->load(environment.get_devicegraph_filename());
	    } break;

	    case ProbeMode::READ_MOCKUP: {
		Mockup::set_mode(Mockup::Mode::PLAYBACK);
		Mockup::load(environment.get_mockup_filename());
		probe(probed);
	    } break;
	}

	y2mil("probed devicegraph begin");
	y2mil(*probed);
	y2mil("probed devicegraph end");

	copy_devicegraph("probed", "staging");
    }

    Storage::Impl::~Impl()
    {
	y2mil("destructed Storage");
    }

    void
    Storage::Impl::probe(Devicegraph* probed)
    {
	SystemInfo systeminfo;

	arch = systeminfo.getArch();

	EtcFstab fstab("/etc");

	// TODO

	for (const string& name : Disk::Impl::probe_disks(systeminfo))
	{
	    Disk* disk = Disk::create(probed, name);
	    disk->get_impl().probe(systeminfo);
	}

	for (Devicegraph::Impl::vertex_descriptor vertex : probed->get_impl().vertices())
	{
	    BlkDevice* blkdevice = dynamic_cast<BlkDevice*>(probed->get_impl()[vertex]);
	    if (!blkdevice)
		continue;

	    if (blkdevice->num_children() != 0)
		continue;

	    Blkid::Entry entry;
	    if (systeminfo.getBlkid().getEntry(blkdevice->get_name(), entry))
	    {
		if (entry.is_fs)
		{
		    // TODO temporary until all fs are implemented
		    if (entry.fs_type != EXT4 && entry.fs_type != BTRFS && entry.fs_type != XFS &&
			entry.fs_type != SWAP)
			continue;

		    Filesystem* filesystem = blkdevice->create_filesystem(entry.fs_type);
		    filesystem->get_impl().probe(systeminfo, fstab);
		}
	    }
	}
    }

    Devicegraph*
    Storage::Impl::get_devicegraph(const string& name)
    {
	if (name == "probed")
	    throw runtime_error("invalid name");

	map<string, Devicegraph>::iterator it = devicegraphs.find(name);
	if (it == devicegraphs.end())
	    throw runtime_error("device graph not found");

	return &it->second;
    }

    const Devicegraph*
    Storage::Impl::get_devicegraph(const string& name) const
    {
	map<string, Devicegraph>::const_iterator it = devicegraphs.find(name);
	if (it == devicegraphs.end())
	    throw runtime_error("device graph not found");

	return &it->second;
    }

    Devicegraph*
    Storage::Impl::get_staging()
    {
	return get_devicegraph("staging");
    }

    const Devicegraph*
    Storage::Impl::get_staging() const
    {
	return get_devicegraph("staging");
    }

    const Devicegraph*
    Storage::Impl::get_probed() const
    {
	return get_devicegraph("probed");
    }

    vector<string>
    Storage::Impl::get_devicegraph_names() const
    {
	vector<string> ret;

	for (const map<string, Devicegraph>::value_type& it : devicegraphs)
	    ret.push_back(it.first);

	return ret;
    }

    Devicegraph*
    Storage::Impl::create_devicegraph(const string& name)
    {
	pair<map<string, Devicegraph>::iterator, bool> tmp =
	    devicegraphs.emplace(piecewise_construct, forward_as_tuple(name),
				 forward_as_tuple(&storage));
	if (!tmp.second)
	    throw logic_error("device graph already exists");

	map<string, Devicegraph>::iterator it = tmp.first;

	return &it->second;
    }

    Devicegraph*
    Storage::Impl::copy_devicegraph(const string& source_name, const string& dest_name)
    {
	const Devicegraph* tmp1 = static_cast<const Impl*>(this)->get_devicegraph(source_name);

	Devicegraph* tmp2 = create_devicegraph(dest_name);

	tmp1->copy(*tmp2);

	return tmp2;
    }

    void
    Storage::Impl::remove_devicegraph(const string& name)
    {
	map<string, Devicegraph>::const_iterator it1 = devicegraphs.find(name);
	if (it1 == devicegraphs.end())
	    throw runtime_error("device graph not found");

	devicegraphs.erase(it1);
    }

    void
    Storage::Impl::restore_devicegraph(const string& name)
    {
	map<string, Devicegraph>::iterator it1 = devicegraphs.find(name);
	if (it1 == devicegraphs.end())
	    throw runtime_error("device graph not found");

	map<string, Devicegraph>::iterator it2 = devicegraphs.find("staging");
	if (it2 == devicegraphs.end())
	    throw runtime_error("device graph not found");

	it1->second.get_impl().swap(it2->second.get_impl());
	devicegraphs.erase(it1);
    }

    bool
    Storage::Impl::exist_devicegraph(const string& name) const
    {
	return devicegraphs.find(name) != devicegraphs.end();
    }

    bool
    Storage::Impl::equal_devicegraph(const string& lhs, const string& rhs) const
    {
	return *get_devicegraph(lhs) == *get_devicegraph(rhs);
    }

    void
    Storage::Impl::check() const
    {
	for (const map<string, Devicegraph>::value_type& key_value : devicegraphs)
	{
	    key_value.second.check();
	}

	// TODO check that a object has the same type in every devicegraph
    }

    string
    Storage::Impl::prepend_rootprefix(const string& mountpoint) const
    {
	if (mountpoint == "swap" || rootprefix.empty())
	    return mountpoint;

	if (mountpoint == "/")
	    return rootprefix;
	else
	    return rootprefix + mountpoint;
    }

    const Actiongraph*
    Storage::Impl::calculate_actiongraph()
    {
	actiongraph.reset(new Actiongraph(storage, get_probed(), get_staging()));

	return actiongraph.get();
    }

    void
    Storage::Impl::commit(const CommitCallbacks* commit_callbacks)
    {
	ST_CHECK_PTR(actiongraph.get());

	actiongraph->get_impl().commit(commit_callbacks);

	// TODO somehow update probed
    }

}
<|endoftext|>