<commit_before>/*
  Copyright (c) 2015, 2016 Genome Research Ltd.

  Author: Jouni Siren <jouni.siren@iki.fi>

  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 <sdsl/construct_sa.hpp>

#include "relative_lcp.h"

using namespace relative;

//------------------------------------------------------------------------------

//#define STORE_PLAIN_DLCP

//------------------------------------------------------------------------------

int
main(int argc, char** argv)
{
  if(argc < 2)
  {
    std::cerr << "Usage: index_dlcp input1 [input2 ...]" << std::endl;
    std::cerr << std::endl;
    return 1;
  }

  std::cout << "Indexing the differential LCP array" << std::endl;
  std::cout << std::endl;

  for(int i = 1; i < argc; i++)
  {
    double start = readTimer();
    std::string base_name = argv[i];
    std::cout << "File: " << base_name << std::endl;
    std::string lcp_file = base_name + LCP_EXTENSION;
    std::ifstream input(lcp_file.c_str(), std::ios_base::binary);
    if(!input)
    {
      std::cerr << "index_dlcp: Cannot open LCP file " << lcp_file << std::endl;
      std::cout << std::endl;
      continue;
    }
    SLArray lcp; lcp.load(input); input.close();
    std::cout << "LCP size: " << lcp.size() << std::endl;
    double megabytes = lcp.size() / MEGABYTE_DOUBLE;

#ifdef STORE_PLAIN_DLCP
    {
      std::vector<int32_t> dlcp_plain(lcp.size(), 0);
      int32_t prev = 0;
      for(size_type i = 1; i < dlcp_plain.size(); i++)
      {
        int32_t curr = lcp[i];
        dlcp_plain[i] = curr - prev;
        prev = curr;
      }
      std::string dlcp_name = base_name + DLCP_EXTENSION;
      std::ofstream out(dlcp_name.c_str(), std::ios_base::binary);
      if(out)
      {
        out.write((char*)(dlcp_plain.data()), dlcp_plain.size() * sizeof(int32_t));
        out.close();
      }
      else
      {
        std::cerr << "index_dlcp: Cannot open DLCP file " << dlcp_name << std::endl;
      }
    }
#endif

    sdsl::int_vector<0> dlcp; dlcp.width(lcp.large.width() + 2);
    differentialArray<SLArray, DiffEncoderNZ>(lcp, dlcp, true);
    sdsl::util::clear(lcp);
    std::cout << "DLCP width: " << (size_type)(dlcp.width()) << std::endl;

    sdsl::int_vector<0> sa;
    sdsl::qsufsort::construct_sa(sa, dlcp); sdsl::util::bit_compress(sa);
    std::cout << "SA width: " << (size_type)(sa.width()) << std::endl;
    store_to_file(sa, base_name + DLCP_INDEX_EXTENSION);

    double seconds = readTimer() - start;
    std::cout << "Index built in " << seconds << " seconds (" << (megabytes / seconds) << " MB/s)" << std::endl;
    std::cout << std::endl;
  }

  return 0;
}

//------------------------------------------------------------------------------
<commit_msg>Output DLCP from index_dlcp<commit_after>/*
  Copyright (c) 2015, 2016 Genome Research Ltd.

  Author: Jouni Siren <jouni.siren@iki.fi>

  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 <sdsl/construct_sa.hpp>

#include "relative_lcp.h"

using namespace relative;

//------------------------------------------------------------------------------

#define STORE_PLAIN_DLCP

//------------------------------------------------------------------------------

int
main(int argc, char** argv)
{
  if(argc < 2)
  {
    std::cerr << "Usage: index_dlcp input1 [input2 ...]" << std::endl;
    std::cerr << std::endl;
    std::exit(EXIT_SUCCESS);
  }

  std::cout << "Indexing the differential LCP array" << std::endl;
  std::cout << std::endl;

  for(int i = 1; i < argc; i++)
  {
    double start = readTimer();
    std::string base_name = argv[i];
    std::cout << "File: " << base_name << std::endl;
    std::string lcp_file = base_name + LCP_EXTENSION;
    std::ifstream input(lcp_file.c_str(), std::ios_base::binary);
    if(!input)
    {
      std::cerr << "index_dlcp: Cannot open LCP file " << lcp_file << std::endl;
      std::cout << std::endl;
      continue;
    }
    SLArray lcp; lcp.load(input); input.close();
    std::cout << "LCP size: " << lcp.size() << std::endl;
    double megabytes = lcp.size() / MEGABYTE_DOUBLE;

#ifdef STORE_PLAIN_DLCP
    {
      std::vector<int32_t> dlcp_plain(lcp.size(), 0);
      int32_t prev = 0;
      for(size_type i = 1; i < dlcp_plain.size(); i++)
      {
        int32_t curr = lcp[i];
        dlcp_plain[i] = curr - prev;
        prev = curr;
      }
      std::string dlcp_name = base_name + DLCP_EXTENSION;
      std::ofstream out(dlcp_name.c_str(), std::ios_base::binary);
      if(out)
      {
        out.write((char*)(dlcp_plain.data()), dlcp_plain.size() * sizeof(int32_t));
        out.close();
      }
      else
      {
        std::cerr << "index_dlcp: Cannot open DLCP file " << dlcp_name << std::endl;
      }
    }
#endif

    sdsl::int_vector<0> dlcp; dlcp.width(lcp.large.width() + 2);
    differentialArray<SLArray, DiffEncoderNZ>(lcp, dlcp, true);
    sdsl::util::clear(lcp);
    std::cout << "DLCP width: " << (size_type)(dlcp.width()) << std::endl;

    sdsl::int_vector<0> sa;
    sdsl::qsufsort::construct_sa(sa, dlcp); sdsl::util::bit_compress(sa);
    std::cout << "SA width: " << (size_type)(sa.width()) << std::endl;
    store_to_file(sa, base_name + DLCP_INDEX_EXTENSION);

    double seconds = readTimer() - start;
    std::cout << "Index built in " << seconds << " seconds (" << (megabytes / seconds) << " MB/s)" << std::endl;
    std::cout << std::endl;
  }

  return 0;
}

//------------------------------------------------------------------------------
<|endoftext|>


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

#include "chrome/browser/extensions/extension_tts_api.h"

#include <atlbase.h>
#include <atlcom.h>
#include <sapi.h>

#include "base/scoped_comptr_win.h"
#include "base/singleton.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"

namespace util = extension_tts_api_util;

class ExtensionTtsPlatformImplWin : public ExtensionTtsPlatformImpl {
 public:
  virtual bool Speak(
      const std::string& utterance,
      const std::string& language,
      const std::string& gender,
      double rate,
      double pitch,
      double volume);

  virtual bool StopSpeaking();

  virtual bool IsSpeaking();

  // Get the single instance of this class.
  static ExtensionTtsPlatformImplWin* GetInstance();

 private:
  ExtensionTtsPlatformImplWin();
  virtual ~ExtensionTtsPlatformImplWin() {}

  ScopedComPtr<ISpVoice> speech_synthesizer_;
  bool paused_;

  friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplWin>;

  DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplWin);
};

// static
ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() {
  return ExtensionTtsPlatformImplWin::GetInstance();
}

bool ExtensionTtsPlatformImplWin::Speak(
    const std::string& src_utterance,
    const std::string& language,
    const std::string& gender,
    double rate,
    double pitch,
    double volume) {
  std::wstring utterance = UTF8ToUTF16(src_utterance);

  if (!speech_synthesizer_)
    return false;

  // Speech API equivalents for kGenderKey and kLanguageNameKey do not
  // exist and thus are not supported.

  if (rate >= 0.0) {
    // The TTS api allows a range of -10 to 10 for speech rate.
    speech_synthesizer_->SetRate(static_cast<int32>(rate * 20 - 10));
  }

  if (pitch >= 0.0) {
    // The TTS api allows a range of -10 to 10 for speech pitch.
    // TODO(dtseng): cleanup if we ever use any other properties that
    // require xml.
    std::wstring pitch_value =
        base::IntToString16(static_cast<int>(pitch * 20 - 10));
    utterance = L"<pitch absmiddle=\"" + pitch_value + L"\">" +
        utterance + L"</pitch>";
  }

  if (volume >= 0.0) {
    // The TTS api allows a range of 0 to 100 for speech volume.
    speech_synthesizer_->SetVolume(static_cast<uint16>(volume * 100));
  }

  if (paused_)
    speech_synthesizer_->Resume();
  speech_synthesizer_->Speak(
      utterance.c_str(), SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL);

  return true;
}

bool ExtensionTtsPlatformImplWin::StopSpeaking() {
  if (!speech_synthesizer_ && !paused_) {
    speech_synthesizer_->Pause();
    paused_ = true;
  }
  return true;
}

bool ExtensionTtsPlatformImplWin::IsSpeaking() {
  return false;
}

ExtensionTtsPlatformImplWin::ExtensionTtsPlatformImplWin()
  : speech_synthesizer_(NULL),
    paused_(false) {
  CoCreateInstance(
      CLSID_SpVoice,
      NULL,
      CLSCTX_SERVER,
      IID_ISpVoice,
      reinterpret_cast<void**>(&speech_synthesizer_));
}

// static
ExtensionTtsPlatformImplWin* ExtensionTtsPlatformImplWin::GetInstance() {
  return Singleton<ExtensionTtsPlatformImplWin>::get();
}
<commit_msg>Fix implementation of StopSpeaking, and implement IsSpeaking, for the Windows-native implementation of the TTS API.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_tts_api.h"

#include <atlbase.h>
#include <atlcom.h>
#include <sapi.h>

#include "base/scoped_comptr_win.h"
#include "base/singleton.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"

namespace util = extension_tts_api_util;

class ExtensionTtsPlatformImplWin : public ExtensionTtsPlatformImpl {
 public:
  virtual bool Speak(
      const std::string& utterance,
      const std::string& language,
      const std::string& gender,
      double rate,
      double pitch,
      double volume);

  virtual bool StopSpeaking();

  virtual bool IsSpeaking();

  // Get the single instance of this class.
  static ExtensionTtsPlatformImplWin* GetInstance();

 private:
  ExtensionTtsPlatformImplWin();
  virtual ~ExtensionTtsPlatformImplWin() {}

  ScopedComPtr<ISpVoice> speech_synthesizer_;
  bool paused_;

  friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplWin>;

  DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplWin);
};

// static
ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() {
  return ExtensionTtsPlatformImplWin::GetInstance();
}

bool ExtensionTtsPlatformImplWin::Speak(
    const std::string& src_utterance,
    const std::string& language,
    const std::string& gender,
    double rate,
    double pitch,
    double volume) {
  std::wstring utterance = UTF8ToUTF16(src_utterance);

  if (!speech_synthesizer_)
    return false;

  // Speech API equivalents for kGenderKey and kLanguageNameKey do not
  // exist and thus are not supported.

  if (rate >= 0.0) {
    // The TTS api allows a range of -10 to 10 for speech rate.
    speech_synthesizer_->SetRate(static_cast<int32>(rate * 20 - 10));
  }

  if (pitch >= 0.0) {
    // The TTS api allows a range of -10 to 10 for speech pitch.
    // TODO(dtseng): cleanup if we ever use any other properties that
    // require xml.
    std::wstring pitch_value =
        base::IntToString16(static_cast<int>(pitch * 20 - 10));
    utterance = L"<pitch absmiddle=\"" + pitch_value + L"\">" +
        utterance + L"</pitch>";
  }

  if (volume >= 0.0) {
    // The TTS api allows a range of 0 to 100 for speech volume.
    speech_synthesizer_->SetVolume(static_cast<uint16>(volume * 100));
  }

  if (paused_)
    speech_synthesizer_->Resume();
  speech_synthesizer_->Speak(
      utterance.c_str(), SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL);

  return true;
}

bool ExtensionTtsPlatformImplWin::StopSpeaking() {
  if (speech_synthesizer_ && !paused_) {
    speech_synthesizer_->Pause();
    paused_ = true;
  }
  return true;
}

bool ExtensionTtsPlatformImplWin::IsSpeaking() {
  if (speech_synthesizer_ && !paused_) {
    SPVOICESTATUS status;
    HRESULT result = speech_synthesizer_->GetStatus(&status, NULL);
    if (result == S_OK && status.dwRunningState == SPRS_IS_SPEAKING)
      return true;
  }
  return false;
}

ExtensionTtsPlatformImplWin::ExtensionTtsPlatformImplWin()
  : speech_synthesizer_(NULL),
    paused_(false) {
  CoCreateInstance(
      CLSID_SpVoice,
      NULL,
      CLSCTX_SERVER,
      IID_ISpVoice,
      reinterpret_cast<void**>(&speech_synthesizer_));
}

// static
ExtensionTtsPlatformImplWin* ExtensionTtsPlatformImplWin::GetInstance() {
  return Singleton<ExtensionTtsPlatformImplWin>::get();
}
<|endoftext|>


<commit_before>/*
  This file is part of Ingen.
  Copyright 2007-2013 David Robillard <http://drobilla.net/>

  Ingen 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 any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef INGEN_ATOM_HPP
#define INGEN_ATOM_HPP

#include <cassert>
#include <cstring>
#include <string>

#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
#include "lv2/lv2plug.in/ns/ext/urid/urid.h"

namespace Ingen {

class Forge;

/**
   A generic typed data container.

   An Atom holds a value with some type and size, both specified by a uint32_t.
   Values with size less than sizeof(void*) are stored inline: no dynamic
   allocation occurs so Atoms may be created in hard real-time threads.
   Otherwise, if the size is larger than sizeof(void*), the value will be
   dynamically allocated in a separate chunk of memory.

   In either case, the data is stored in a binary compatible format to LV2_Atom
   (i.e., if the value is dynamically allocated, the header is repeated there).

   @ingroup raul
*/
class Atom {
public:
	Atom()  { _atom.size = 0; _atom.type = 0; _body.ptr = NULL; }
	~Atom() { dealloc(); }

	/** Contruct a raw atom.
	 *
	 * Typically this is not used directly, use Forge methods to make atoms.
	 */
	Atom(uint32_t size, LV2_URID type, const void* body) {
		_atom.size = size;
		_atom.type = type;
		_body.ptr  = NULL;
		if (is_reference()) {
			_body.ptr = (LV2_Atom*)malloc(sizeof(LV2_Atom) + size);
			memcpy(_body.ptr, &_atom, sizeof(LV2_Atom));
		}
		if (body) {
			memcpy(get_body(), body, size);
		}
	}

	Atom(const Atom& copy)
		: _atom(copy._atom)
	{
		if (is_reference()) {
			_body.ptr = (LV2_Atom*)malloc(sizeof(LV2_Atom) + _atom.size);
			memcpy(_body.ptr, copy._body.ptr, sizeof(LV2_Atom) + _atom.size);
		} else {
			memcpy(&_body.val, &copy._body.val, sizeof(_body.val));
		}
	}

	Atom& operator=(const Atom& other) {
		if (&other == this) {
			return *this;
		}
		dealloc();
		_atom = other._atom;
		if (is_reference()) {
			_body.ptr = (LV2_Atom*)malloc(sizeof(LV2_Atom) + _atom.size);
			memcpy(_body.ptr, other._body.ptr, sizeof(LV2_Atom) + _atom.size);
		} else {
			memcpy(&_body.val, &other._body.val, sizeof(_body.val));
		}
		return *this;
	}

	inline bool operator==(const Atom& other) const {
		if (is_reference()) {
			return !memcmp(_body.ptr, other._body.ptr, sizeof(LV2_Atom) + _atom.size);
		}
		return (_atom.type == other._atom.type &&
		        _atom.size == other._atom.size &&
		        _body.val == other._body.val);
	}

	inline bool operator!=(const Atom& other) const {
		return !operator==(other);
	}

	inline bool operator<(const Atom& other) const {
		if (_atom.type == other._atom.type) {
			if (is_reference()) {
				return memcmp(_body.ptr, other._body.ptr, _atom.size) < 0;
			} else {
				return memcmp(&_body.val, &other._body.val, _atom.size) < 0;
			}
		}
		return type() < other.type();
	}

	inline uint32_t size()     const { return _atom.size; }
	inline LV2_URID type()     const { return _atom.type; }
	inline bool     is_valid() const { return _atom.type; }

	inline const void* get_body() const {
		return is_reference() ? (void*)(_body.ptr + 1) : &_body.val;
	}

	inline void* get_body() {
		return is_reference() ? (void*)(_body.ptr + 1) : &_body.val;
	}

	template <typename T> const T& get() const {
		assert(size() == sizeof(T));
		return *static_cast<const T*>(get_body());
	}

	template <typename T> const T* ptr() const {
		return static_cast<const T*>(get_body());
	}

	const LV2_Atom* atom() const {
		return is_reference() ? _body.ptr : &_atom;
	}

private:
	friend class Forge;

	/** Free dynamically allocated value, if applicable. */
	inline void dealloc() {
		if (is_reference()) {
			free(_body.ptr);
		}
	}

	/** Return true iff this value is dynamically allocated. */
	inline bool is_reference() const {
		return _atom.size > sizeof(_body.val);
	}

	LV2_Atom _atom;
	union {
		intptr_t  val;
		LV2_Atom* ptr;
	} _body;
};

} // namespace Ingen

#endif // INGEN_ATOM_HPP
<commit_msg>Fix crufty comments.<commit_after>/*
  This file is part of Ingen.
  Copyright 2007-2013 David Robillard <http://drobilla.net/>

  Ingen 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 any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef INGEN_ATOM_HPP
#define INGEN_ATOM_HPP

#include <cassert>
#include <cstring>
#include <string>

#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
#include "lv2/lv2plug.in/ns/ext/urid/urid.h"

namespace Ingen {

class Forge;

/**
   A generic typed data container.

   An Atom holds a value with some type and size, both specified by a uint32_t.
   Values with size less than sizeof(void*) are stored inline: no dynamic
   allocation occurs so Atoms may be created in hard real-time threads.
   Otherwise, if the size is larger than sizeof(void*), the value will be
   dynamically allocated in a separate chunk of memory.

   In either case, the data is stored in a binary compatible format to LV2_Atom
   (i.e., if the value is dynamically allocated, the header is repeated there).
*/
class Atom {
public:
	Atom()  { _atom.size = 0; _atom.type = 0; _body.ptr = NULL; }
	~Atom() { dealloc(); }

	/** Construct a raw atom.
	 *
	 * Typically this is not used directly, use Forge methods to make atoms.
	 */
	Atom(uint32_t size, LV2_URID type, const void* body) {
		_atom.size = size;
		_atom.type = type;
		_body.ptr  = NULL;
		if (is_reference()) {
			_body.ptr = (LV2_Atom*)malloc(sizeof(LV2_Atom) + size);
			memcpy(_body.ptr, &_atom, sizeof(LV2_Atom));
		}
		if (body) {
			memcpy(get_body(), body, size);
		}
	}

	Atom(const Atom& copy)
		: _atom(copy._atom)
	{
		if (is_reference()) {
			_body.ptr = (LV2_Atom*)malloc(sizeof(LV2_Atom) + _atom.size);
			memcpy(_body.ptr, copy._body.ptr, sizeof(LV2_Atom) + _atom.size);
		} else {
			memcpy(&_body.val, &copy._body.val, sizeof(_body.val));
		}
	}

	Atom& operator=(const Atom& other) {
		if (&other == this) {
			return *this;
		}
		dealloc();
		_atom = other._atom;
		if (is_reference()) {
			_body.ptr = (LV2_Atom*)malloc(sizeof(LV2_Atom) + _atom.size);
			memcpy(_body.ptr, other._body.ptr, sizeof(LV2_Atom) + _atom.size);
		} else {
			memcpy(&_body.val, &other._body.val, sizeof(_body.val));
		}
		return *this;
	}

	inline bool operator==(const Atom& other) const {
		if (is_reference()) {
			return !memcmp(_body.ptr, other._body.ptr, sizeof(LV2_Atom) + _atom.size);
		}
		return (_atom.type == other._atom.type &&
		        _atom.size == other._atom.size &&
		        _body.val == other._body.val);
	}

	inline bool operator!=(const Atom& other) const {
		return !operator==(other);
	}

	inline bool operator<(const Atom& other) const {
		if (_atom.type == other._atom.type) {
			if (is_reference()) {
				return memcmp(_body.ptr, other._body.ptr, _atom.size) < 0;
			} else {
				return memcmp(&_body.val, &other._body.val, _atom.size) < 0;
			}
		}
		return type() < other.type();
	}

	inline uint32_t size()     const { return _atom.size; }
	inline LV2_URID type()     const { return _atom.type; }
	inline bool     is_valid() const { return _atom.type; }

	inline const void* get_body() const {
		return is_reference() ? (void*)(_body.ptr + 1) : &_body.val;
	}

	inline void* get_body() {
		return is_reference() ? (void*)(_body.ptr + 1) : &_body.val;
	}

	template <typename T> const T& get() const {
		assert(size() == sizeof(T));
		return *static_cast<const T*>(get_body());
	}

	template <typename T> const T* ptr() const {
		return static_cast<const T*>(get_body());
	}

	const LV2_Atom* atom() const {
		return is_reference() ? _body.ptr : &_atom;
	}

private:
	friend class Forge;

	/** Free dynamically allocated value, if applicable. */
	inline void dealloc() {
		if (is_reference()) {
			free(_body.ptr);
		}
	}

	/** Return true iff this value is dynamically allocated. */
	inline bool is_reference() const {
		return _atom.size > sizeof(_body.val);
	}

	LV2_Atom _atom;
	union {
		intptr_t  val;
		LV2_Atom* ptr;
	} _body;
};

} // namespace Ingen

#endif // INGEN_ATOM_HPP
<|endoftext|>


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

#include "chrome/browser/ui/webui/chrome_url_data_manager.h"

#include <vector>

#include "base/i18n/rtl.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h"
#include "content/browser/browser_thread.h"
#include "grit/platform_locale_settings.h"
#include "ui/base/l10n/l10n_util.h"

#if defined(OS_WIN)
#include "base/win/windows_version.h"
#endif

// static
base::Lock ChromeURLDataManager::delete_lock_;

// static
ChromeURLDataManager::DataSources* ChromeURLDataManager::data_sources_ = NULL;

// Invoked on the IO thread to do the actual adding of the DataSource.
static void AddDataSourceOnIOThread(
    const base::Callback<ChromeURLDataManagerBackend*(void)>& backend,
    scoped_refptr<ChromeURLDataManager::DataSource> data_source) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  backend.Run()->AddDataSource(data_source.get());
}

ChromeURLDataManager::ChromeURLDataManager(
      const base::Callback<ChromeURLDataManagerBackend*(void)>& backend)
    : backend_(backend) {
}

ChromeURLDataManager::~ChromeURLDataManager() {
}

void ChromeURLDataManager::AddDataSource(DataSource* source) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableFunction(AddDataSourceOnIOThread,
                          backend_,
                          make_scoped_refptr(source)));
}

// static
void ChromeURLDataManager::DeleteDataSources() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DataSources sources;
  {
    base::AutoLock lock(delete_lock_);
    if (!data_sources_)
      return;
    data_sources_->swap(sources);
  }
  for (size_t i = 0; i < sources.size(); ++i)
    delete sources[i];
}

// static
void ChromeURLDataManager::DeleteDataSource(const DataSource* data_source) {
  // Invoked when a DataSource is no longer referenced and needs to be deleted.
  if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    // We're on the UI thread, delete right away.
    delete data_source;
    return;
  }

  // We're not on the UI thread, add the DataSource to the list of DataSources
  // to delete.
  bool schedule_delete = false;
  {
    base::AutoLock lock(delete_lock_);
    if (!data_sources_)
      data_sources_ = new DataSources();
    schedule_delete = data_sources_->empty();
    data_sources_->push_back(data_source);
  }
  if (schedule_delete) {
    // Schedule a task to delete the DataSource back on the UI thread.
    BrowserThread::PostTask(BrowserThread::UI,
                            FROM_HERE,
                            NewRunnableFunction(
                                &ChromeURLDataManager::DeleteDataSources));
  }
}

// static
bool ChromeURLDataManager::IsScheduledForDeletion(
    const DataSource* data_source) {
  base::AutoLock lock(delete_lock_);
  if (!data_sources_)
    return false;
  return std::find(data_sources_->begin(), data_sources_->end(), data_source) !=
      data_sources_->end();
}

ChromeURLDataManager::DataSource::DataSource(const std::string& source_name,
                                             MessageLoop* message_loop)
    : source_name_(source_name),
      message_loop_(message_loop),
      backend_(NULL) {
}

ChromeURLDataManager::DataSource::~DataSource() {
}

void ChromeURLDataManager::DataSource::SendResponse(int request_id,
                                                    RefCountedMemory* bytes) {
  if (IsScheduledForDeletion(this)) {
    // We're scheduled for deletion. Servicing the request would result in
    // this->AddRef being invoked, even though the ref count is 0 and 'this' is
    // about to be deleted. If the AddRef were allowed through, when 'this' is
    // released it would be deleted again.
    //
    // This scenario occurs with DataSources that make history requests. Such
    // DataSources do a history query in |StartDataRequest| and the request is
    // live until the object is deleted (history requests don't up the ref
    // count). This means it's entirely possible for the DataSource to invoke
    // |SendResponse| between the time when there are no more refs and the time
    // when the object is deleted.
    return;
  }
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableMethod(this, &DataSource::SendResponseOnIOThread,
                        request_id, make_scoped_refptr(bytes)));
}

MessageLoop* ChromeURLDataManager::DataSource::MessageLoopForRequestPath(
    const std::string& path) const {
  return message_loop_;
}

bool ChromeURLDataManager::DataSource::ShouldReplaceExistingSource() const {
  return true;
}

// static
void ChromeURLDataManager::DataSource::SetFontAndTextDirection(
    DictionaryValue* localized_strings) {
  localized_strings->SetString("fontfamily",
      l10n_util::GetStringUTF16(IDS_WEB_FONT_FAMILY));

  int web_font_size_id = IDS_WEB_FONT_SIZE;
#if defined(OS_WIN)
  // Some fonts used for some languages changed a lot in terms of the font
  // metric in Vista. So, we need to use different size before Vista.
  if (base::win::GetVersion() < base::win::VERSION_VISTA)
    web_font_size_id = IDS_WEB_FONT_SIZE_XP;
#endif
  localized_strings->SetString("fontsize",
      l10n_util::GetStringUTF16(web_font_size_id));

  localized_strings->SetString("textdirection",
      base::i18n::IsRTL() ? "rtl" : "ltr");
}

void ChromeURLDataManager::DataSource::SendResponseOnIOThread(
    int request_id,
    scoped_refptr<RefCountedMemory> bytes) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (backend_)
    backend_->DataAvailable(request_id, bytes);
}
<commit_msg>Fix potential leak<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/chrome_url_data_manager.h"

#include <vector>

#include "base/i18n/rtl.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h"
#include "content/browser/browser_thread.h"
#include "grit/platform_locale_settings.h"
#include "ui/base/l10n/l10n_util.h"

#if defined(OS_WIN)
#include "base/win/windows_version.h"
#endif

// static
base::Lock ChromeURLDataManager::delete_lock_;

// static
ChromeURLDataManager::DataSources* ChromeURLDataManager::data_sources_ = NULL;

// Invoked on the IO thread to do the actual adding of the DataSource.
static void AddDataSourceOnIOThread(
    const base::Callback<ChromeURLDataManagerBackend*(void)>& backend,
    scoped_refptr<ChromeURLDataManager::DataSource> data_source) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  backend.Run()->AddDataSource(data_source.get());
}

ChromeURLDataManager::ChromeURLDataManager(
      const base::Callback<ChromeURLDataManagerBackend*(void)>& backend)
    : backend_(backend) {
}

ChromeURLDataManager::~ChromeURLDataManager() {
}

void ChromeURLDataManager::AddDataSource(DataSource* source) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableFunction(AddDataSourceOnIOThread,
                          backend_,
                          make_scoped_refptr(source)));
}

// static
void ChromeURLDataManager::DeleteDataSources() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DataSources sources;
  {
    base::AutoLock lock(delete_lock_);
    if (!data_sources_)
      return;
    data_sources_->swap(sources);
  }
  for (size_t i = 0; i < sources.size(); ++i)
    delete sources[i];
}

// static
void ChromeURLDataManager::DeleteDataSource(const DataSource* data_source) {
  // Invoked when a DataSource is no longer referenced and needs to be deleted.
  if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    // We're on the UI thread, delete right away.
    delete data_source;
    return;
  }

  // We're not on the UI thread, add the DataSource to the list of DataSources
  // to delete.
  bool schedule_delete = false;
  {
    base::AutoLock lock(delete_lock_);
    if (!data_sources_)
      data_sources_ = new DataSources();
    schedule_delete = data_sources_->empty();
    data_sources_->push_back(data_source);
  }
  if (schedule_delete) {
    // Schedule a task to delete the DataSource back on the UI thread.
    BrowserThread::PostTask(BrowserThread::UI,
                            FROM_HERE,
                            NewRunnableFunction(
                                &ChromeURLDataManager::DeleteDataSources));
  }
}

// static
bool ChromeURLDataManager::IsScheduledForDeletion(
    const DataSource* data_source) {
  base::AutoLock lock(delete_lock_);
  if (!data_sources_)
    return false;
  return std::find(data_sources_->begin(), data_sources_->end(), data_source) !=
      data_sources_->end();
}

ChromeURLDataManager::DataSource::DataSource(const std::string& source_name,
                                             MessageLoop* message_loop)
    : source_name_(source_name),
      message_loop_(message_loop),
      backend_(NULL) {
}

ChromeURLDataManager::DataSource::~DataSource() {
}

void ChromeURLDataManager::DataSource::SendResponse(int request_id,
                                                    RefCountedMemory* bytes) {
  // Take a ref-pointer on entry so byte->Release() will always get called.
  scoped_refptr<RefCountedMemory> bytes_ptr(bytes);
  if (IsScheduledForDeletion(this)) {
    // We're scheduled for deletion. Servicing the request would result in
    // this->AddRef being invoked, even though the ref count is 0 and 'this' is
    // about to be deleted. If the AddRef were allowed through, when 'this' is
    // released it would be deleted again.
    //
    // This scenario occurs with DataSources that make history requests. Such
    // DataSources do a history query in |StartDataRequest| and the request is
    // live until the object is deleted (history requests don't up the ref
    // count). This means it's entirely possible for the DataSource to invoke
    // |SendResponse| between the time when there are no more refs and the time
    // when the object is deleted.
    return;
  }
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableMethod(this, &DataSource::SendResponseOnIOThread,
                        request_id, bytes_ptr));
}

MessageLoop* ChromeURLDataManager::DataSource::MessageLoopForRequestPath(
    const std::string& path) const {
  return message_loop_;
}

bool ChromeURLDataManager::DataSource::ShouldReplaceExistingSource() const {
  return true;
}

// static
void ChromeURLDataManager::DataSource::SetFontAndTextDirection(
    DictionaryValue* localized_strings) {
  localized_strings->SetString("fontfamily",
      l10n_util::GetStringUTF16(IDS_WEB_FONT_FAMILY));

  int web_font_size_id = IDS_WEB_FONT_SIZE;
#if defined(OS_WIN)
  // Some fonts used for some languages changed a lot in terms of the font
  // metric in Vista. So, we need to use different size before Vista.
  if (base::win::GetVersion() < base::win::VERSION_VISTA)
    web_font_size_id = IDS_WEB_FONT_SIZE_XP;
#endif
  localized_strings->SetString("fontsize",
      l10n_util::GetStringUTF16(web_font_size_id));

  localized_strings->SetString("textdirection",
      base::i18n::IsRTL() ? "rtl" : "ltr");
}

void ChromeURLDataManager::DataSource::SendResponseOnIOThread(
    int request_id,
    scoped_refptr<RefCountedMemory> bytes) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (backend_)
    backend_->DataAvailable(request_id, bytes);
}
<|endoftext|>


<commit_before>// This file will only be compiled with clang into llvm bitcode
// Generated bitcode will likely get inline for performance.

#include <atomic>

#define FORCEINLINE __attribute__((always_inline))

constexpr int taichi_max_num_indices = 4;
constexpr int taichi_max_num_args = 8;

using ContextArgType = long long;

struct Context {
  void *buffer;
  ContextArgType args[taichi_max_num_args];
  void *leaves;
  int num_leaves;
  void *cpu_profiler;
};

extern "C" {

ContextArgType context_get_arg(Context *context, int arg_id) {
  return context->args[arg_id];
}

void *context_get_buffer(Context *context) {
  return context->buffer;
}

int printf(const char *, ...);

using float32 = float;

float32 atomic_add_cpu_f32(volatile float32 *dest, float32 inc) {
  float32 old_val;
  float32 new_val;
  do {
    old_val = *dest;
    new_val = old_val + inc;
#if defined(__clang__)
  } while (!__atomic_compare_exchange(dest, &old_val, &new_val, true,
                                      std::memory_order::memory_order_seq_cst,
                                      std::memory_order::memory_order_seq_cst));
#else
  } while (!__atomic_compare_exchange((float32 *)dest, &old_val, &new_val, true,
                                      std::memory_order::memory_order_seq_cst,
                                      std::memory_order::memory_order_seq_cst));
#endif
  return old_val;
}

struct NodeRef {
  int indices[taichi_max_num_indices];
  int loop_bounds[2];
  void *node;
};

int *noderef_get_index_ptr(NodeRef *noderef, int i) {
  return &noderef->indices[i];
}

int *noderef_get_loop_bound_ptr(NodeRef *noderef, int i) {
  return &noderef->loop_bounds[i];
}

void **noderef_get_node_ptr_ptr(NodeRef *noderef) {
  return &noderef->node;
}

#define STRUCT_FIELD(S, F)                              \
  extern "C" decltype(S::F) S##_get_##F(S *s) {         \
    return s->F;                                        \
  }                                                     \
  extern "C" void S##_set_##F(S *s, decltype(S::F) f) { \
    s->F = f;                                           \
  }

/*
#define STRUCT_FUNCTION(S, F)
extern "C" decltype()
 */

// These structures are accessible by both the LLVM backend and this C++ runtime
// file here (for building complex runtime functions in C++)

struct DenseStruct {
  void *node;
  bool bitmasked;
  int morton_dim;
  std::size_t element_size;
  int forking_factor;  // n
};

STRUCT_FIELD(DenseStruct, node)
STRUCT_FIELD(DenseStruct, bitmasked)
STRUCT_FIELD(DenseStruct, morton_dim)
STRUCT_FIELD(DenseStruct, element_size)
STRUCT_FIELD(DenseStruct, forking_factor)

void DenseStruct_activate(DenseStruct *s, int i) {
}

void *DenseStruct_lookup(DenseStruct *s, int i) {
  return (char *)s->node + s->element_size * i;
}

void *taichi_allocate_aligned(std::size_t size, int alignment);

void *taichi_allocate(std::size_t size) {
  return taichi_allocate_aligned(size, 1);
}

void ___stubs___() {
  printf("");
  taichi_allocate(1);
  taichi_allocate_aligned(1, 1);
}

struct Node {
  void *node;
  int coordinates[taichi_max_num_indices];
};

STRUCT_FIELD(Node, node);
// STRUCT_FIELD(Node, coordinates);

struct NodeList {
  Node *list;
  int tail;
};

void NodeList_initialize(NodeList *node_list) {
  node_list->list = (Node *)taichi_allocate(1024 * 1024 * 1024);
  node_list->tail = 0;
}

void NodeList_insert(NodeList *node_list, Node *node) {
  node_list->list[node_list->tail] = *node;
  node_list->tail++;
}

void NodeList_clear(NodeList *node_list) {
  node_list->tail = 0;
}

// Is "runtime" a correct name, even if it is created after the data layout is
// materialized?
struct Runtime {
  NodeList *lists[1024];
};

void Runtime_initialize(Runtime **runtime_ptr, int num_snodes) {
  *runtime_ptr = (Runtime *)taichi_allocate(sizeof(Runtime));
  Runtime *runtime = *runtime_ptr;
  printf("Initializing runtime with %d snodes\n", num_snodes);
  for (int i = 0; i < num_snodes; i++) {
    runtime->lists[i] = (NodeList *)taichi_allocate(sizeof(NodeList));
    NodeList_initialize(runtime->lists[i]);
  }
  printf("Runtime initialized.\n");
}

/*
 *
void unitied_allocator_create();

void unified_allocator_free();

void *create_noderef_vector() {
  return new std::vector<NodeRef>;
}

void destory_noderef_vector(void *vec) {
  auto ptr = (std::vector<NodeRef> *)vec;
  delete ptr;
}

int noderef_vector_size(void *vec) {
  auto ptr = (std::vector<NodeRef> *)vec;
  return ptr->size();
}

NodeRef *get_noderef_vector_elem(void *vec, int i) {
  auto ptr = (std::vector<NodeRef> *)vec;
  return &(*ptr)[i];
}
*/
}
<commit_msg>runtime struct array member read/write<commit_after>// This file will only be compiled with clang into llvm bitcode
// Generated bitcode will likely get inline for performance.

#include <type_traits>
#include <atomic>

#define FORCEINLINE __attribute__((always_inline))

constexpr int taichi_max_num_indices = 4;
constexpr int taichi_max_num_args = 8;

using ContextArgType = long long;

struct Context {
  void *buffer;
  ContextArgType args[taichi_max_num_args];
  void *leaves;
  int num_leaves;
  void *cpu_profiler;
};

extern "C" {

ContextArgType context_get_arg(Context *context, int arg_id) {
  return context->args[arg_id];
}

void *context_get_buffer(Context *context) {
  return context->buffer;
}

int printf(const char *, ...);

using float32 = float;

float32 atomic_add_cpu_f32(volatile float32 *dest, float32 inc) {
  float32 old_val;
  float32 new_val;
  do {
    old_val = *dest;
    new_val = old_val + inc;
#if defined(__clang__)
  } while (!__atomic_compare_exchange(dest, &old_val, &new_val, true,
                                      std::memory_order::memory_order_seq_cst,
                                      std::memory_order::memory_order_seq_cst));
#else
  } while (!__atomic_compare_exchange((float32 *)dest, &old_val, &new_val, true,
                                      std::memory_order::memory_order_seq_cst,
                                      std::memory_order::memory_order_seq_cst));
#endif
  return old_val;
}

#define STRUCT_FIELD(S, F)                              \
  extern "C" decltype(S::F) S##_get_##F(S *s) {         \
    return s->F;                                        \
  }                                                     \
  extern "C" void S##_set_##F(S *s, decltype(S::F) f) { \
    s->F = f;                                           \
  }

#define STRUCT_FIELD_ARRAY(S, F)                                             \
  extern "C" std::remove_all_extents_t<decltype(S::F)> S##_get_##F(S *s,     \
                                                                   int i) {  \
    return s->F[i];                                                          \
  }                                                                          \
  extern "C" void S##_set_##F(S *s, int i,                                   \
                              std::remove_all_extents_t<decltype(S::F)> f) { \
    s->F[i] = f;                                                             \
  }

/*
#define STRUCT_FUNCTION(S, F)
extern "C" decltype()
 */

// These structures are accessible by both the LLVM backend and this C++ runtime
// file here (for building complex runtime functions in C++)

struct DenseStruct {
  void *node;
  bool bitmasked;
  int morton_dim;
  std::size_t element_size;
  int forking_factor;  // n
};

STRUCT_FIELD(DenseStruct, node)
STRUCT_FIELD(DenseStruct, bitmasked)
STRUCT_FIELD(DenseStruct, morton_dim)
STRUCT_FIELD(DenseStruct, element_size)
STRUCT_FIELD(DenseStruct, forking_factor)

void DenseStruct_activate(DenseStruct *s, int i) {
}

void *DenseStruct_lookup(DenseStruct *s, int i) {
  return (char *)s->node + s->element_size * i;
}

void *taichi_allocate_aligned(std::size_t size, int alignment);

void *taichi_allocate(std::size_t size) {
  return taichi_allocate_aligned(size, 1);
}

void ___stubs___() {
  printf("");
  taichi_allocate(1);
  taichi_allocate_aligned(1, 1);
}

struct Node {
  void *node;
  int loop_bounds[2];
  int coordinates[taichi_max_num_indices];
};

STRUCT_FIELD(Node, node);
STRUCT_FIELD_ARRAY(Node, loop_bounds);
STRUCT_FIELD_ARRAY(Node, coordinates);

struct NodeList {
  Node *list;
  int tail;
};

void NodeList_initialize(NodeList *node_list) {
  node_list->list = (Node *)taichi_allocate(1024 * 1024 * 1024);
  node_list->tail = 0;
}

void NodeList_insert(NodeList *node_list, Node *node) {
  node_list->list[node_list->tail] = *node;
  node_list->tail++;
}

void NodeList_clear(NodeList *node_list) {
  node_list->tail = 0;
}

// Is "runtime" a correct name, even if it is created after the data layout is
// materialized?
struct Runtime {
  NodeList *lists[1024];
};

void Runtime_initialize(Runtime **runtime_ptr, int num_snodes) {
  *runtime_ptr = (Runtime *)taichi_allocate(sizeof(Runtime));
  Runtime *runtime = *runtime_ptr;
  printf("Initializing runtime with %d snodes\n", num_snodes);
  for (int i = 0; i < num_snodes; i++) {
    runtime->lists[i] = (NodeList *)taichi_allocate(sizeof(NodeList));
    NodeList_initialize(runtime->lists[i]);
  }
  printf("Runtime initialized.\n");
}
}
<|endoftext|>


<commit_before>#include <iostream>
#include <algorithm>

#include <sys/wait.h>
#include <unistd.h>

#include "store.hh"
#include "globals.hh"
#include "db.hh"
#include "archive.hh"
#include "pathlocks.hh"

/* Nix database. */
static Database nixDB;

/* Database tables. */

/* dbValidPaths :: Path -> ()

   The existence of a key $p$ indicates that path $p$ is valid (that
   is, produced by a succesful build). */
static TableId dbValidPaths;

/* dbSuccessors :: Path -> Path

   Each pair $(p_1, p_2)$ in this mapping records the fact that the
   Nix expression stored at path $p_1$ has a successor expression
   stored at path $p_2$.

   Note that a term $y$ is a successor of $x$ iff there exists a
   sequence of rewrite steps that rewrites $x$ into $y$.
*/
static TableId dbSuccessors;

/* dbSuccessorsRev :: Path -> [Path]

   The reverse mapping of dbSuccessors (i.e., it stores the
   predecessors of a Nix expression).
*/
static TableId dbSuccessorsRev;

/* dbSubstitutes :: Path -> [Path]

   Each pair $(p, [ps])$ tells Nix that it can realise any of the
   Nix expressions stored at paths $ps$ to produce a path $p$.

   The main purpose of this is for distributed caching of derivates.
   One system can compute a derivate and put it on a website (as a Nix
   archive), for instance, and then another system can register a
   substitute for that derivate.  The substitute in this case might be
   a Nix expression that fetches the Nix archive.
*/
static TableId dbSubstitutes;

/* dbSubstitutesRev :: Path -> [Path]

   The reverse mapping of dbSubstitutes.
*/
static TableId dbSubstitutesRev;

void openDB()
{
    nixDB.open(nixDBPath);
    dbValidPaths = nixDB.openTable("validpaths");
    dbSuccessors = nixDB.openTable("successors");
    dbSuccessorsRev = nixDB.openTable("successors-rev");
    dbSubstitutes = nixDB.openTable("substitutes");
    dbSubstitutesRev = nixDB.openTable("substitutes-rev");
}

void initDB()
{
}

void createStoreTransaction(Transaction & txn)
{
    Transaction txn2(nixDB);
    txn2.moveTo(txn);
}

/* Path copying. */

struct CopySink : DumpSink
{
    int fd;
    virtual void operator () (const unsigned char * data, unsigned int len)
    {
        writeFull(fd, data, len);
    }
};

struct CopySource : RestoreSource
{
    int fd;
    virtual void operator () (unsigned char * data, unsigned int len)
    {
        readFull(fd, data, len);
    }
};

void copyPath(const Path & src, const Path & dst)
{
    debug(format("copying `%1%' to `%2%'") % src % dst);

    /* Unfortunately C++ doesn't support coprocedures, so we have no
       nice way to chain CopySink and CopySource together.  Instead we
       fork off a child to run the sink.  (Fork-less platforms should
       use a thread). */

    /* Create a pipe. */
    int fds[2];
    if (pipe(fds) == -1) throw SysError("creating pipe");

    /* Fork. */
    pid_t pid;
    switch (pid = fork()) {

    case -1:
        throw SysError("unable to fork");

    case 0: /* child */
        try {
            close(fds[1]);
            CopySource source;
            source.fd = fds[0];
            restorePath(dst, source);
            _exit(0);
        }  catch (exception & e) {
            cerr << "error: " << e.what() << endl;
        }
        _exit(1);
    }

    close(fds[0]);

    /* Parent. */

    CopySink sink;
    sink.fd = fds[1];
    dumpPath(src, sink);

    /* Wait for the child to finish. */
    int status;
    if (waitpid(pid, &status, 0) != pid)
        throw SysError("waiting for child");

    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
        throw Error("cannot copy file: child died");
}

static bool isValidPathTxn(const Path & path, const Transaction & txn)
{
    string s;
    return nixDB.queryString(txn, dbValidPaths, path, s);
}

bool isValidPath(const Path & path)
{
    return isValidPathTxn(path, noTxn);
}

static bool isUsablePathTxn(const Path & path, const Transaction & txn)
{
    if (isValidPathTxn(path, txn)) return true;
    Paths subs;
    nixDB.queryStrings(txn, dbSubstitutes, path, subs);
    return subs.size() > 0;
}

void registerSuccessor(const Transaction & txn,
    const Path & srcPath, const Path & sucPath)
{
    if (!isUsablePathTxn(sucPath, txn))	throw Error(
	format("path `%1%' cannot be a successor, since it is not usable")
	% sucPath);

    Path known;
    if (nixDB.queryString(txn, dbSuccessors, srcPath, known) &&
        known != sucPath)
    {
        throw Error(format(
            "the `impossible' happened: expression in path "
            "`%1%' appears to have multiple successors "
            "(known `%2%', new `%3%'")
            % srcPath % known % sucPath);
    }

    Paths revs;
    nixDB.queryStrings(txn, dbSuccessorsRev, sucPath, revs);
    if (find(revs.begin(), revs.end(), srcPath) == revs.end())
        revs.push_back(srcPath);

    nixDB.setString(txn, dbSuccessors, srcPath, sucPath);
    nixDB.setStrings(txn, dbSuccessorsRev, sucPath, revs);
}

bool querySuccessor(const Path & srcPath, Path & sucPath)
{
    return nixDB.queryString(noTxn, dbSuccessors, srcPath, sucPath);
}

Paths queryPredecessors(const Path & sucPath)
{
    Paths revs;
    nixDB.queryStrings(noTxn, dbSuccessorsRev, sucPath, revs);
    return revs;
}

void registerSubstitute(const Path & srcPath, const Path & subPath)
{
    if (!isValidPathTxn(subPath, noTxn)) throw Error(
	format("path `%1%' cannot be a substitute, since it is not valid")
	% subPath);

    Transaction txn(nixDB);

    Paths subs;
    nixDB.queryStrings(txn, dbSubstitutes, srcPath, subs);

    if (find(subs.begin(), subs.end(), subPath) != subs.end()) {
        /* Nothing to do if the substitute is already known. */
        txn.abort();
        return;
    }
    subs.push_front(subPath); /* new substitutes take precedence */

    Paths revs;
    nixDB.queryStrings(txn, dbSubstitutesRev, subPath, revs);
    if (find(revs.begin(), revs.end(), srcPath) == revs.end())
        revs.push_back(srcPath);

    nixDB.setStrings(txn, dbSubstitutes, srcPath, subs);
    nixDB.setStrings(txn, dbSubstitutesRev, subPath, revs);

    txn.commit();
}

Paths querySubstitutes(const Path & srcPath)
{
    Paths subPaths;
    nixDB.queryStrings(noTxn, dbSubstitutes, srcPath, subPaths);
    return subPaths;
}

void registerValidPath(const Transaction & txn, const Path & _path)
{
    Path path(canonPath(_path));
    debug(format("registering path `%1%'") % path);
    nixDB.setString(txn, dbValidPaths, path, "");
}

static void setOrClearStrings(Transaction & txn,
    TableId table, const string & key, const Strings & value)
{
    if (value.size() > 0)
        nixDB.setStrings(txn, table, key, value);
    else
        nixDB.delPair(txn, table, key);
}

static void invalidatePath(const Path & path, Transaction & txn)
{
    debug(format("unregistering path `%1%'") % path);

    nixDB.delPair(txn, dbValidPaths, path);

    /* Remove any successor mappings to this path (but not *from*
       it). */
    Paths revs;
    nixDB.queryStrings(txn, dbSuccessorsRev, path, revs);
    for (Paths::iterator i = revs.begin(); i != revs.end(); ++i)
        nixDB.delPair(txn, dbSuccessors, *i);
    nixDB.delPair(txn, dbSuccessorsRev, path);

    /* Remove any substitute mappings to this path. */
    revs.clear();
    nixDB.queryStrings(txn, dbSubstitutesRev, path, revs);
    for (Paths::iterator i = revs.begin(); i != revs.end(); ++i) {
        Paths subs;
        nixDB.queryStrings(txn, dbSubstitutes, *i, subs);
        if (find(subs.begin(), subs.end(), path) == subs.end())
            throw Error("integrity error in substitutes mapping");
        subs.remove(path);
        setOrClearStrings(txn, dbSubstitutes, *i, subs);

	/* If path *i now has no substitutes left, and is not valid,
	   then it too should be invalidated.  This is because it may
	   be a substitute or successor. */
	if (subs.size() == 0 && !isValidPathTxn(*i, txn))
	    invalidatePath(*i, txn);
    }
    nixDB.delPair(txn, dbSubstitutesRev, path);
}

static bool isInPrefix(const string & path, const string & _prefix)
{
    string prefix = canonPath(_prefix + "/");
    return string(path, 0, prefix.size()) == prefix;
}

Path addToStore(const Path & _srcPath)
{
    Path srcPath(absPath(_srcPath));
    debug(format("adding `%1%' to the store") % srcPath);

    Hash h = hashPath(srcPath);

    string baseName = baseNameOf(srcPath);
    Path dstPath = canonPath(nixStore + "/" + (string) h + "-" + baseName);

    if (!isValidPath(dstPath)) {

        /* The first check above is an optimisation to prevent
           unnecessary lock acquisition. */

        PathSet lockPaths;
        lockPaths.insert(dstPath);
        PathLocks outputLock(lockPaths);

        if (!isValidPath(dstPath)) {
            copyPath(srcPath, dstPath);

            Transaction txn(nixDB);
            registerValidPath(txn, dstPath);
            txn.commit();
        }

        outputLock.setDeletion(true);
    }

    return dstPath;
}

void addTextToStore(const Path & dstPath, const string & s)
{
    if (!isValidPath(dstPath)) {

        PathSet lockPaths;
        lockPaths.insert(dstPath);
        PathLocks outputLock(lockPaths);

        if (!isValidPath(dstPath)) {
            writeStringToFile(dstPath, s);

            Transaction txn(nixDB);
            registerValidPath(txn, dstPath);
            txn.commit();
        }

        outputLock.setDeletion(true);
    }
}

void deleteFromStore(const Path & _path)
{
    Path path(canonPath(_path));

    if (!isInPrefix(path, nixStore))
        throw Error(format("path `%1%' is not in the store") % path);

    Transaction txn(nixDB);
    invalidatePath(path, txn);
    txn.commit();

    deletePath(path);
}

void verifyStore()
{
    Transaction txn(nixDB);

    Paths paths;
    PathSet validPaths;
    nixDB.enumTable(txn, dbValidPaths, paths);

    for (Paths::iterator i = paths.begin(); i != paths.end(); ++i) {
        Path path = *i;
        if (!pathExists(path)) {
            debug(format("path `%1%' disappeared") % path);
            invalidatePath(path, txn);
        } else
            validPaths.insert(path);
    }

    /* !!! the code below does not allow transitive substitutes.
       I.e., if B is a substitute of A, then B must be a valid path.
       B cannot itself be invalid but have a substitute. */

    /* "Usable" paths are those that are valid or have a substitute.
       These are the paths that are allowed to appear in the
       right-hand side of a sute mapping. */
    PathSet usablePaths(validPaths);

    /* Check that the values of the substitute mappings are valid
       paths. */
    Paths subs;
    nixDB.enumTable(txn, dbSubstitutes, subs);
    for (Paths::iterator i = subs.begin(); i != subs.end(); ++i) {
        Paths subPaths, subPaths2;
        nixDB.queryStrings(txn, dbSubstitutes, *i, subPaths);
        for (Paths::iterator j = subPaths.begin(); j != subPaths.end(); ++j)
            if (validPaths.find(*j) == validPaths.end())
                debug(format("found substitute mapping to non-existent path `%1%'") % *j);
            else
                subPaths2.push_back(*j);
        if (subPaths.size() != subPaths2.size())
            setOrClearStrings(txn, dbSubstitutes, *i, subPaths2);
	if (subPaths2.size() > 0)
	    usablePaths.insert(*i);
    }

    /* Check that the keys of the reverse substitute mappings are
       valid paths. */
    Paths rsubs;
    nixDB.enumTable(txn, dbSubstitutesRev, rsubs);
    for (Paths::iterator i = rsubs.begin(); i != rsubs.end(); ++i) {
        if (validPaths.find(*i) == validPaths.end()) {
            debug(format("found reverse substitute mapping for non-existent path `%1%'") % *i);
            nixDB.delPair(txn, dbSubstitutesRev, *i);
        }
    }

    /* Check that the values of the successor mappings are usable
       paths. */
    Paths sucs;
    nixDB.enumTable(txn, dbSuccessors, sucs);
    for (Paths::iterator i = sucs.begin(); i != sucs.end(); ++i) {
        /* Note that *i itself does not have to be valid, just its
           successor. */
        Path sucPath;
        if (nixDB.queryString(txn, dbSuccessors, *i, sucPath) &&
            usablePaths.find(sucPath) == usablePaths.end())
        {
            debug(format("found successor mapping to non-existent path `%1%'") % sucPath);
            nixDB.delPair(txn, dbSuccessors, *i);
        }
    }

    /* Check that the keys of the reverse successor mappings are valid
       paths. */
    Paths rsucs;
    nixDB.enumTable(txn, dbSuccessorsRev, rsucs);
    for (Paths::iterator i = rsucs.begin(); i != rsucs.end(); ++i) {
        if (usablePaths.find(*i) == usablePaths.end()) {
            debug(format("found reverse successor mapping for non-existent path `%1%'") % *i);
            nixDB.delPair(txn, dbSuccessorsRev, *i);
        }
    }

    txn.commit();
}
<commit_msg>* Print error messages, not debug messages.<commit_after>#include <iostream>
#include <algorithm>

#include <sys/wait.h>
#include <unistd.h>

#include "store.hh"
#include "globals.hh"
#include "db.hh"
#include "archive.hh"
#include "pathlocks.hh"

/* Nix database. */
static Database nixDB;

/* Database tables. */

/* dbValidPaths :: Path -> ()

   The existence of a key $p$ indicates that path $p$ is valid (that
   is, produced by a succesful build). */
static TableId dbValidPaths;

/* dbSuccessors :: Path -> Path

   Each pair $(p_1, p_2)$ in this mapping records the fact that the
   Nix expression stored at path $p_1$ has a successor expression
   stored at path $p_2$.

   Note that a term $y$ is a successor of $x$ iff there exists a
   sequence of rewrite steps that rewrites $x$ into $y$.
*/
static TableId dbSuccessors;

/* dbSuccessorsRev :: Path -> [Path]

   The reverse mapping of dbSuccessors (i.e., it stores the
   predecessors of a Nix expression).
*/
static TableId dbSuccessorsRev;

/* dbSubstitutes :: Path -> [Path]

   Each pair $(p, [ps])$ tells Nix that it can realise any of the
   Nix expressions stored at paths $ps$ to produce a path $p$.

   The main purpose of this is for distributed caching of derivates.
   One system can compute a derivate and put it on a website (as a Nix
   archive), for instance, and then another system can register a
   substitute for that derivate.  The substitute in this case might be
   a Nix expression that fetches the Nix archive.
*/
static TableId dbSubstitutes;

/* dbSubstitutesRev :: Path -> [Path]

   The reverse mapping of dbSubstitutes.
*/
static TableId dbSubstitutesRev;

void openDB()
{
    nixDB.open(nixDBPath);
    dbValidPaths = nixDB.openTable("validpaths");
    dbSuccessors = nixDB.openTable("successors");
    dbSuccessorsRev = nixDB.openTable("successors-rev");
    dbSubstitutes = nixDB.openTable("substitutes");
    dbSubstitutesRev = nixDB.openTable("substitutes-rev");
}

void initDB()
{
}

void createStoreTransaction(Transaction & txn)
{
    Transaction txn2(nixDB);
    txn2.moveTo(txn);
}

/* Path copying. */

struct CopySink : DumpSink
{
    int fd;
    virtual void operator () (const unsigned char * data, unsigned int len)
    {
        writeFull(fd, data, len);
    }
};

struct CopySource : RestoreSource
{
    int fd;
    virtual void operator () (unsigned char * data, unsigned int len)
    {
        readFull(fd, data, len);
    }
};

void copyPath(const Path & src, const Path & dst)
{
    debug(format("copying `%1%' to `%2%'") % src % dst);

    /* Unfortunately C++ doesn't support coprocedures, so we have no
       nice way to chain CopySink and CopySource together.  Instead we
       fork off a child to run the sink.  (Fork-less platforms should
       use a thread). */

    /* Create a pipe. */
    int fds[2];
    if (pipe(fds) == -1) throw SysError("creating pipe");

    /* Fork. */
    pid_t pid;
    switch (pid = fork()) {

    case -1:
        throw SysError("unable to fork");

    case 0: /* child */
        try {
            close(fds[1]);
            CopySource source;
            source.fd = fds[0];
            restorePath(dst, source);
            _exit(0);
        }  catch (exception & e) {
            cerr << "error: " << e.what() << endl;
        }
        _exit(1);
    }

    close(fds[0]);

    /* Parent. */

    CopySink sink;
    sink.fd = fds[1];
    dumpPath(src, sink);

    /* Wait for the child to finish. */
    int status;
    if (waitpid(pid, &status, 0) != pid)
        throw SysError("waiting for child");

    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
        throw Error("cannot copy file: child died");
}

static bool isValidPathTxn(const Path & path, const Transaction & txn)
{
    string s;
    return nixDB.queryString(txn, dbValidPaths, path, s);
}

bool isValidPath(const Path & path)
{
    return isValidPathTxn(path, noTxn);
}

static bool isUsablePathTxn(const Path & path, const Transaction & txn)
{
    if (isValidPathTxn(path, txn)) return true;
    Paths subs;
    nixDB.queryStrings(txn, dbSubstitutes, path, subs);
    return subs.size() > 0;
}

void registerSuccessor(const Transaction & txn,
    const Path & srcPath, const Path & sucPath)
{
    if (!isUsablePathTxn(sucPath, txn))	throw Error(
	format("path `%1%' cannot be a successor, since it is not usable")
	% sucPath);

    Path known;
    if (nixDB.queryString(txn, dbSuccessors, srcPath, known) &&
        known != sucPath)
    {
        throw Error(format(
            "the `impossible' happened: expression in path "
            "`%1%' appears to have multiple successors "
            "(known `%2%', new `%3%'")
            % srcPath % known % sucPath);
    }

    Paths revs;
    nixDB.queryStrings(txn, dbSuccessorsRev, sucPath, revs);
    if (find(revs.begin(), revs.end(), srcPath) == revs.end())
        revs.push_back(srcPath);

    nixDB.setString(txn, dbSuccessors, srcPath, sucPath);
    nixDB.setStrings(txn, dbSuccessorsRev, sucPath, revs);
}

bool querySuccessor(const Path & srcPath, Path & sucPath)
{
    return nixDB.queryString(noTxn, dbSuccessors, srcPath, sucPath);
}

Paths queryPredecessors(const Path & sucPath)
{
    Paths revs;
    nixDB.queryStrings(noTxn, dbSuccessorsRev, sucPath, revs);
    return revs;
}

void registerSubstitute(const Path & srcPath, const Path & subPath)
{
    if (!isValidPathTxn(subPath, noTxn)) throw Error(
	format("path `%1%' cannot be a substitute, since it is not valid")
	% subPath);

    Transaction txn(nixDB);

    Paths subs;
    nixDB.queryStrings(txn, dbSubstitutes, srcPath, subs);

    if (find(subs.begin(), subs.end(), subPath) != subs.end()) {
        /* Nothing to do if the substitute is already known. */
        txn.abort();
        return;
    }
    subs.push_front(subPath); /* new substitutes take precedence */

    Paths revs;
    nixDB.queryStrings(txn, dbSubstitutesRev, subPath, revs);
    if (find(revs.begin(), revs.end(), srcPath) == revs.end())
        revs.push_back(srcPath);

    nixDB.setStrings(txn, dbSubstitutes, srcPath, subs);
    nixDB.setStrings(txn, dbSubstitutesRev, subPath, revs);

    txn.commit();
}

Paths querySubstitutes(const Path & srcPath)
{
    Paths subPaths;
    nixDB.queryStrings(noTxn, dbSubstitutes, srcPath, subPaths);
    return subPaths;
}

void registerValidPath(const Transaction & txn, const Path & _path)
{
    Path path(canonPath(_path));
    debug(format("registering path `%1%'") % path);
    nixDB.setString(txn, dbValidPaths, path, "");
}

static void setOrClearStrings(Transaction & txn,
    TableId table, const string & key, const Strings & value)
{
    if (value.size() > 0)
        nixDB.setStrings(txn, table, key, value);
    else
        nixDB.delPair(txn, table, key);
}

static void invalidatePath(const Path & path, Transaction & txn)
{
    debug(format("unregistering path `%1%'") % path);

    nixDB.delPair(txn, dbValidPaths, path);

    /* Remove any successor mappings to this path (but not *from*
       it). */
    Paths revs;
    nixDB.queryStrings(txn, dbSuccessorsRev, path, revs);
    for (Paths::iterator i = revs.begin(); i != revs.end(); ++i)
        nixDB.delPair(txn, dbSuccessors, *i);
    nixDB.delPair(txn, dbSuccessorsRev, path);

    /* Remove any substitute mappings to this path. */
    revs.clear();
    nixDB.queryStrings(txn, dbSubstitutesRev, path, revs);
    for (Paths::iterator i = revs.begin(); i != revs.end(); ++i) {
        Paths subs;
        nixDB.queryStrings(txn, dbSubstitutes, *i, subs);
        if (find(subs.begin(), subs.end(), path) == subs.end())
            throw Error("integrity error in substitutes mapping");
        subs.remove(path);
        setOrClearStrings(txn, dbSubstitutes, *i, subs);

	/* If path *i now has no substitutes left, and is not valid,
	   then it too should be invalidated.  This is because it may
	   be a substitute or successor. */
	if (subs.size() == 0 && !isValidPathTxn(*i, txn))
	    invalidatePath(*i, txn);
    }
    nixDB.delPair(txn, dbSubstitutesRev, path);
}

static bool isInPrefix(const string & path, const string & _prefix)
{
    string prefix = canonPath(_prefix + "/");
    return string(path, 0, prefix.size()) == prefix;
}

Path addToStore(const Path & _srcPath)
{
    Path srcPath(absPath(_srcPath));
    debug(format("adding `%1%' to the store") % srcPath);

    Hash h = hashPath(srcPath);

    string baseName = baseNameOf(srcPath);
    Path dstPath = canonPath(nixStore + "/" + (string) h + "-" + baseName);

    if (!isValidPath(dstPath)) {

        /* The first check above is an optimisation to prevent
           unnecessary lock acquisition. */

        PathSet lockPaths;
        lockPaths.insert(dstPath);
        PathLocks outputLock(lockPaths);

        if (!isValidPath(dstPath)) {
            copyPath(srcPath, dstPath);

            Transaction txn(nixDB);
            registerValidPath(txn, dstPath);
            txn.commit();
        }

        outputLock.setDeletion(true);
    }

    return dstPath;
}

void addTextToStore(const Path & dstPath, const string & s)
{
    if (!isValidPath(dstPath)) {

        PathSet lockPaths;
        lockPaths.insert(dstPath);
        PathLocks outputLock(lockPaths);

        if (!isValidPath(dstPath)) {
            writeStringToFile(dstPath, s);

            Transaction txn(nixDB);
            registerValidPath(txn, dstPath);
            txn.commit();
        }

        outputLock.setDeletion(true);
    }
}

void deleteFromStore(const Path & _path)
{
    Path path(canonPath(_path));

    if (!isInPrefix(path, nixStore))
        throw Error(format("path `%1%' is not in the store") % path);

    Transaction txn(nixDB);
    invalidatePath(path, txn);
    txn.commit();

    deletePath(path);
}

void verifyStore()
{
    Transaction txn(nixDB);

    Paths paths;
    PathSet validPaths;
    nixDB.enumTable(txn, dbValidPaths, paths);

    for (Paths::iterator i = paths.begin(); i != paths.end(); ++i) {
        Path path = *i;
        if (!pathExists(path)) {
            printMsg(lvlError, format("path `%1%' disappeared") % path);
            invalidatePath(path, txn);
        } else
            validPaths.insert(path);
    }

    /* !!! the code below does not allow transitive substitutes.
       I.e., if B is a substitute of A, then B must be a valid path.
       B cannot itself be invalid but have a substitute. */

    /* "Usable" paths are those that are valid or have a substitute.
       These are the paths that are allowed to appear in the
       right-hand side of a sute mapping. */
    PathSet usablePaths(validPaths);

    /* Check that the values of the substitute mappings are valid
       paths. */
    Paths subs;
    nixDB.enumTable(txn, dbSubstitutes, subs);
    for (Paths::iterator i = subs.begin(); i != subs.end(); ++i) {
        Paths subPaths, subPaths2;
        nixDB.queryStrings(txn, dbSubstitutes, *i, subPaths);
        for (Paths::iterator j = subPaths.begin(); j != subPaths.end(); ++j)
            if (validPaths.find(*j) == validPaths.end())
                printMsg(lvlError,
                    format("found substitute mapping to non-existent path `%1%'") % *j);
            else
                subPaths2.push_back(*j);
        if (subPaths.size() != subPaths2.size())
            setOrClearStrings(txn, dbSubstitutes, *i, subPaths2);
	if (subPaths2.size() > 0)
	    usablePaths.insert(*i);
    }

    /* Check that the keys of the reverse substitute mappings are
       valid paths. */
    Paths rsubs;
    nixDB.enumTable(txn, dbSubstitutesRev, rsubs);
    for (Paths::iterator i = rsubs.begin(); i != rsubs.end(); ++i) {
        if (validPaths.find(*i) == validPaths.end()) {
            printMsg(lvlError,
                format("found reverse substitute mapping for non-existent path `%1%'") % *i);
            nixDB.delPair(txn, dbSubstitutesRev, *i);
        }
    }

    /* Check that the values of the successor mappings are usable
       paths. */
    Paths sucs;
    nixDB.enumTable(txn, dbSuccessors, sucs);
    for (Paths::iterator i = sucs.begin(); i != sucs.end(); ++i) {
        /* Note that *i itself does not have to be valid, just its
           successor. */
        Path sucPath;
        if (nixDB.queryString(txn, dbSuccessors, *i, sucPath) &&
            usablePaths.find(sucPath) == usablePaths.end())
        {
            printMsg(lvlError,
                format("found successor mapping to non-existent path `%1%'") % sucPath);
            nixDB.delPair(txn, dbSuccessors, *i);
        }
    }

    /* Check that the keys of the reverse successor mappings are valid
       paths. */
    Paths rsucs;
    nixDB.enumTable(txn, dbSuccessorsRev, rsucs);
    for (Paths::iterator i = rsucs.begin(); i != rsucs.end(); ++i) {
        if (usablePaths.find(*i) == usablePaths.end()) {
            printMsg(lvlError,
                format("found reverse successor mapping for non-existent path `%1%'") % *i);
            nixDB.delPair(txn, dbSuccessorsRev, *i);
        }
    }

    txn.commit();
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>
#include <memory>
#include <stdio.h>
#include <utility>
#include <vector>

using namespace std;

struct stencil_type {
    int offset;
    int move;
    vector<short> cells;
};

static const int HEAPSIZE=30000;
static const int CODESIZE=30000;
static const int STACKSIZE=3000;
static const int MAXCHAR=255;
static const unsigned char STENCIL_INSTRUCTION = 'O';

static unsigned char DATA[HEAPSIZE] = {};
static unsigned char CODE[CODESIZE] = {};
static int JUMPS[CODESIZE] = {};
static stencil_type STENCILS[CODESIZE] = {};

static int STACK[STACKSIZE] = {};

stencil_type build_stencil() {
    stencil_type stencil;
    stencil.cells.push_back(0);
    int cursor = 0;
    int left_offset = 0;

    char next_char;
    while ((next_char = getchar_unlocked()) != EOF) {
        switch(next_char) {
            case '<':
                if (cursor > 0) {
                    --cursor;
                } else {
                    stencil.cells.insert(stencil.cells.begin(), 0);
                    ++left_offset;
                }
                break;
            case '>':
                ++cursor;
                if (cursor >= (int) (stencil.cells.size())) {
                    stencil.cells.push_back(0);
                }
                break;
            case '+':
                ++stencil.cells[cursor];
                break;
            case '-':
                --stencil.cells[cursor];
                break;
            case '[':
            case ']':
            case '.':
            case ',':
                goto exit_loop;
                break;
        }
    }
    exit_loop:
    stencil.move = cursor - left_offset;
    stencil.offset = left_offset;

    ungetc(next_char, stdin);

    return stencil;
}

unsigned char parse_run(char character) {
    unsigned char number = 1;
    char next_char;
    while ((next_char = getchar_unlocked()) == character &&
           number < 255) {
        ++number;
    }
    ungetc(next_char, stdin);
    return number;
}

void parse_and_compile() {
    int *stack_ptr = STACK;
    char input;

    for (int code_counter = 0; (input = getchar_unlocked()) != EOF;) {
        switch(input) {
            case '<':
            case '>':
            case '+':
            case '-':
                ungetc(input, stdin);
                CODE[code_counter] = STENCIL_INSTRUCTION;
                STENCILS[code_counter] = build_stencil();
                ++code_counter;
                break;
            case '.':
            case ',':
                CODE[code_counter] = input;
                ++code_counter;
                break;
            case '[':
                *stack_ptr = code_counter;
                ++stack_ptr;
                CODE[code_counter] = input;
                ++code_counter;
                break;
            case ']':
                --stack_ptr;
                JUMPS[*stack_ptr] = code_counter;
                JUMPS[code_counter] = *stack_ptr;
                CODE[code_counter] = input;
                ++code_counter;
                break;
        }
    }
}

void run() {
    unsigned char *tmp_data_ptr;
    unsigned char *data_ptr = DATA;
    stencil_type *stencil;
    for (unsigned char *code_ptr = CODE;
         code_ptr < &CODE[CODESIZE];
         code_ptr++) {
        switch(*code_ptr) {
            case STENCIL_INSTRUCTION:
                stencil = &STENCILS[code_ptr-CODE];
                tmp_data_ptr = data_ptr - stencil->offset;
                data_ptr += stencil->move;

                for (unsigned int i= 0; i < stencil->cells.size(); ++i) {
                    *tmp_data_ptr = (unsigned char) *tmp_data_ptr +
                        stencil->cells[i];
                    ++tmp_data_ptr;
                }
                break;
            case '<':
                ++code_ptr;
                data_ptr -= *code_ptr;
                break;
            case '>':
                ++code_ptr;
                data_ptr += *code_ptr;
                break;
            case '+':
                ++code_ptr;
                *data_ptr += *code_ptr;
                break;
            case '-':
                ++code_ptr;
                *data_ptr -= *code_ptr;
                break;
            case '[':
                if (!*data_ptr) {
                    code_ptr =
                        (unsigned char*) (CODE + JUMPS[code_ptr-CODE]);
                }
                break;
            case ']':
                if (*data_ptr) {
                    code_ptr =
                        (unsigned char*) (CODE + JUMPS[code_ptr-CODE]);
                }
                break;
            case '.':
                putchar_unlocked(*data_ptr);
                break;
            case ',':
                *data_ptr = getchar_unlocked();
                break;
        }
    }
}

void print_code() {
    vector<unsigned char> instructions = {
        '<', '>', '+', '-', ',',
        '.', '[', ']', STENCIL_INSTRUCTION
        };
    for (auto& c : CODE) {
        if (c > 0) {
            if (find(instructions.begin(), instructions.end(), c) !=
                instructions.end()) {
                cout << c;
            } else {
                cout << (int) c;
            }
        }
    }
    cout << "\n";
}

void print_vec(const std::vector<short>& vec)
{
    for (auto x: vec) {
         cout << ' ' << x;
    }
    cout << '\n';
}

int main() {
    parse_and_compile();
    //print_code();
    run();
    return 0;
}
<commit_msg>Move away from vector slowed :(  :  ~15s runtime<commit_after>#include <algorithm>
#include <iostream>
#include <memory>
#include <stdio.h>
#include <utility>
#include <vector>

using namespace std;

struct stencil_type {
    int offset;
    int move;
    unsigned int length;
    unique_ptr<short[]> cells;
};

static const int HEAPSIZE=30000;
static const int CODESIZE=30000;
static const int STACKSIZE=3000;
static const int MAXCHAR=255;
static const unsigned char STENCIL_INSTRUCTION = 'O';

static unsigned char DATA[HEAPSIZE] = {};
static unsigned char CODE[CODESIZE] = {};
static int JUMPS[CODESIZE] = {};
static stencil_type STENCILS[CODESIZE] = {};

static int STACK[STACKSIZE] = {};

stencil_type build_stencil() {
    stencil_type stencil;
    vector<short> stencil_buffer(1,0);
    int cursor = 0;
    int left_offset = 0;

    char next_char;
    while ((next_char = getchar_unlocked()) != EOF) {
        switch(next_char) {
            case '<':
                if (cursor > 0) {
                    --cursor;
                } else {
                    stencil_buffer.insert(stencil_buffer.begin(), 0);
                    ++left_offset;
                }
                break;
            case '>':
                ++cursor;
                if (cursor >= (int) (stencil_buffer.size())) {
                    stencil_buffer.push_back(0);
                }
                break;
            case '+':
                ++stencil_buffer[cursor];
                break;
            case '-':
                --stencil_buffer[cursor];
                break;
            case '[':
            case ']':
            case '.':
            case ',':
                goto exit_loop;
                break;
        }
    }
    exit_loop:
    ungetc(next_char, stdin);

    stencil.move = cursor - left_offset;
    stencil.offset = left_offset;
    stencil.length = stencil_buffer.size();
    stencil.cells.reset(new short[stencil.length]());
    copy(stencil_buffer.begin(), stencil_buffer.end(), stencil.cells.get());

    return stencil;
}

void parse_and_compile() {
    int *stack_ptr = STACK;
    char input;

    for (int code_counter = 0; (input = getchar_unlocked()) != EOF;) {
        switch(input) {
            case '<':
            case '>':
            case '+':
            case '-':
                ungetc(input, stdin);
                CODE[code_counter] = STENCIL_INSTRUCTION;
                STENCILS[code_counter] = build_stencil();
                ++code_counter;
                break;
            case '.':
            case ',':
                CODE[code_counter] = input;
                ++code_counter;
                break;
            case '[':
                *stack_ptr = code_counter;
                ++stack_ptr;
                CODE[code_counter] = input;
                ++code_counter;
                break;
            case ']':
                --stack_ptr;
                JUMPS[*stack_ptr] = code_counter;
                JUMPS[code_counter] = *stack_ptr;
                CODE[code_counter] = input;
                ++code_counter;
                break;
        }
    }
}

void run() {
    unsigned char *tmp_data_ptr;
    unsigned char *data_ptr = DATA;
    stencil_type *stencil;
    for (unsigned char *code_ptr = CODE;
         code_ptr < &CODE[CODESIZE];
         code_ptr++) {
        switch(*code_ptr) {
            case STENCIL_INSTRUCTION:
                stencil = &STENCILS[code_ptr-CODE];
                tmp_data_ptr = data_ptr - stencil->offset;
                data_ptr += stencil->move;

                for (unsigned int i= 0; i < stencil->length; ++i) {
                    *tmp_data_ptr = (unsigned char) *tmp_data_ptr +
                        stencil->cells[i];
                    ++tmp_data_ptr;
                }
                break;
            case '[':
                if (!*data_ptr) {
                    code_ptr =
                        (unsigned char*) (CODE + JUMPS[code_ptr-CODE]);
                }
                break;
            case ']':
                if (*data_ptr) {
                    code_ptr =
                        (unsigned char*) (CODE + JUMPS[code_ptr-CODE]);
                }
                break;
            case '.':
                putchar_unlocked(*data_ptr);
                break;
            case ',':
                *data_ptr = getchar_unlocked();
                break;
        }
    }
}

void print_code() {
    vector<unsigned char> instructions = {
        '<', '>', '+', '-', ',',
        '.', '[', ']', STENCIL_INSTRUCTION
        };
    for (auto& c : CODE) {
        if (c > 0) {
            if (find(instructions.begin(), instructions.end(), c) !=
                instructions.end()) {
                cout << c;
            } else {
                cout << (int) c;
            }
        }
    }
    cout << "\n";
}

void print_vec(const std::vector<short>& vec)
{
    for (auto x: vec) {
         cout << ' ' << x;
    }
    cout << '\n';
}

int main() {
    parse_and_compile();
    //print_code();
    run();
    return 0;
}
<|endoftext|>