<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: registry.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: vg $ $Date: 2007-03-26 14:09:38 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _REGISTRY_HXX_
#include "registry.hxx"
#endif

#include <Shlwapi.h>
#include <assert.h>
#include <algorithm>

#pragma warning(disable : 4786 4350)

//-----------------------------------------------------
/** Create instance and open the specified Registry key

    @throws  RegistryWriteAccessDenyException
             RegistryAccessDenyException
             RegistryKeyNotFoundException
*/
RegistryKeyImpl::RegistryKeyImpl(HKEY RootKey, const std::wstring& KeyName) :
    m_hRootKey(RootKey),
    m_hSubKey(0),
    m_KeyName(KeyName),
    m_IsWriteable(false)
{
}

//-----------------------------------------------------
/** Create instance and open the specified Registry key

    @throws  RegistryWriteAccessDenyException
             RegistryAccessDenyException
             RegistryKeyNotFoundException
*/
RegistryKeyImpl::RegistryKeyImpl(HKEY RootKey) :
    m_hRootKey(RootKey),
    m_hSubKey(0),
    m_IsWriteable(false)
{
}

//-----------------------------------------------------
/** Create an instances of the specified Registry key,
    the key is assumed to be already opened.
*/
RegistryKeyImpl::RegistryKeyImpl(HKEY RootKey, HKEY SubKey, const std::wstring& KeyName, bool Writeable) :
    m_hRootKey(RootKey),
    m_hSubKey(SubKey),
    m_KeyName(KeyName),
    m_IsWriteable(Writeable)
{
}

//-----------------------------------------------------
/**
*/
RegistryKeyImpl::~RegistryKeyImpl()
{
    if (IsOpen())
        Close();
}

//############################################
// Queries
//############################################

//-----------------------------------------------------
/** The name of the key at hand, maybe empty
    if this is any of the root keys
*/
std::wstring RegistryKeyImpl::GetName() const
{
    return m_KeyName;
}

//-----------------------------------------------------
/**
*/
bool RegistryKeyImpl::IsOpen() const
{
    return m_hSubKey != 0;
}

//-----------------------------------------------------
/** Is this one of the root keys
    HKEY_CLASSES_ROOT
    HKEY_CURRENT_USER
    etc.
*/
bool RegistryKeyImpl::IsRootKey() const
{
    return (0 == m_KeyName.length());
}

//-----------------------------------------------------
/** Do we have write access on the key at hand
*/
bool RegistryKeyImpl::IsWriteable() const
{
    return m_IsWriteable;
}

//-----------------------------------------------------
/** Convenience function to determine if the
    Registry key at hand has the specified
    value

    @precond IsOpen = true

    throws RegistryAccessDenyException
*/
bool RegistryKeyImpl::HasValue(const std::wstring& Name) const
{
    StringListPtr names = GetSubValueNames();

    StringList::iterator iter_end = names->end();
    StringList::iterator iter = std::find(names->begin(), iter_end, Name);

    return (iter != iter_end);
}

struct CompareNamesCaseInsensitive
{
    CompareNamesCaseInsensitive(const std::wstring& Name) :
        name_(Name)
    {}

    bool operator() (const std::wstring& value)
    {
        return (0 == StrCmpI(value.c_str(), name_.c_str()));
    }

    std::wstring name_;
};

//-----------------------------------------------------
/** Convenience function to determine if the
    Registry key at hand has the specified
    sub-key

    @precond IsOpen = true

    throws RegistryAccessDenyException
*/
bool RegistryKeyImpl::HasSubKey(const std::wstring& Name) const
{
    StringListPtr names = GetSubKeyNames();

    StringList::iterator iter_end = names->end();
    StringList::iterator iter = std::find_if(names->begin(), iter_end, CompareNamesCaseInsensitive(Name));

    return (iter != iter_end);
}

//-----------------------------------------------------
/**
*/
void RegistryKeyImpl::Close()
{
    if (RegCloseKey(m_hSubKey) != ERROR_SUCCESS) {
        assert(false);
    }

    m_hSubKey = 0;
    m_IsWriteable = false;
}

//-----------------------------------------------------
/** Copies the specified value from RegistryKey to
    the registry key at hand, if a value with this
    name already exist under the registry key at hand
    it will be overwritten

    @precond IsOpen = true
             IsWriteable = true
             RegistryKey.HasSubValue(Name) = true

    @throws RegistryIOException
            RegistryWriteAccessDeniedException
            RegistryValueNotFoundException
*/
void RegistryKeyImpl::CopyValue(const RegistryKey& RegistryKey, const std::wstring& Name)
{
    assert(RegistryKey->HasValue(Name));
#ifdef __MINGW32__
    SetValue((const RegistryValue&)(RegistryKey->GetValue(Name)));
#else
    SetValue(RegistryKey->GetValue(Name));
#endif
    assert(HasValue(Name));
}

/** Copies the specified value from RegistryKey to
    the registry key at hand under a new name,
    if a value with this name already exist there
    it will be overwritten

    @precond IsOpen = true
             IsWriteable = true
             RegistryKey.HasSubValue(Name) = true

    @throws RegistryIOException
            RegistryWriteAccessDeniedException
            RegistryValueNotFoundException
*/
void RegistryKeyImpl::CopyValue(const RegistryKey& RegistryKey, const std::wstring& Name, const std::wstring& NewName)
{
    assert(RegistryKey->HasValue(Name));

    RegistryValue RegVal = RegistryKey->GetValue(Name);
    RegVal->SetName(NewName);
    SetValue(RegVal);

    assert(HasValue(NewName));
}
<commit_msg>INTEGRATION: CWS mingwport06 (1.6.48); FILE MERGED 2007/08/24 13:12:57 vg 1.6.48.1: #i75499# pragma is for MSVC<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: registry.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: kz $ $Date: 2007-09-06 13:30:47 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _REGISTRY_HXX_
#include "registry.hxx"
#endif

#include <Shlwapi.h>
#include <assert.h>
#include <algorithm>

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

//-----------------------------------------------------
/** Create instance and open the specified Registry key

    @throws  RegistryWriteAccessDenyException
             RegistryAccessDenyException
             RegistryKeyNotFoundException
*/
RegistryKeyImpl::RegistryKeyImpl(HKEY RootKey, const std::wstring& KeyName) :
    m_hRootKey(RootKey),
    m_hSubKey(0),
    m_KeyName(KeyName),
    m_IsWriteable(false)
{
}

//-----------------------------------------------------
/** Create instance and open the specified Registry key

    @throws  RegistryWriteAccessDenyException
             RegistryAccessDenyException
             RegistryKeyNotFoundException
*/
RegistryKeyImpl::RegistryKeyImpl(HKEY RootKey) :
    m_hRootKey(RootKey),
    m_hSubKey(0),
    m_IsWriteable(false)
{
}

//-----------------------------------------------------
/** Create an instances of the specified Registry key,
    the key is assumed to be already opened.
*/
RegistryKeyImpl::RegistryKeyImpl(HKEY RootKey, HKEY SubKey, const std::wstring& KeyName, bool Writeable) :
    m_hRootKey(RootKey),
    m_hSubKey(SubKey),
    m_KeyName(KeyName),
    m_IsWriteable(Writeable)
{
}

//-----------------------------------------------------
/**
*/
RegistryKeyImpl::~RegistryKeyImpl()
{
    if (IsOpen())
        Close();
}

//############################################
// Queries
//############################################

//-----------------------------------------------------
/** The name of the key at hand, maybe empty
    if this is any of the root keys
*/
std::wstring RegistryKeyImpl::GetName() const
{
    return m_KeyName;
}

//-----------------------------------------------------
/**
*/
bool RegistryKeyImpl::IsOpen() const
{
    return m_hSubKey != 0;
}

//-----------------------------------------------------
/** Is this one of the root keys
    HKEY_CLASSES_ROOT
    HKEY_CURRENT_USER
    etc.
*/
bool RegistryKeyImpl::IsRootKey() const
{
    return (0 == m_KeyName.length());
}

//-----------------------------------------------------
/** Do we have write access on the key at hand
*/
bool RegistryKeyImpl::IsWriteable() const
{
    return m_IsWriteable;
}

//-----------------------------------------------------
/** Convenience function to determine if the
    Registry key at hand has the specified
    value

    @precond IsOpen = true

    throws RegistryAccessDenyException
*/
bool RegistryKeyImpl::HasValue(const std::wstring& Name) const
{
    StringListPtr names = GetSubValueNames();

    StringList::iterator iter_end = names->end();
    StringList::iterator iter = std::find(names->begin(), iter_end, Name);

    return (iter != iter_end);
}

struct CompareNamesCaseInsensitive
{
    CompareNamesCaseInsensitive(const std::wstring& Name) :
        name_(Name)
    {}

    bool operator() (const std::wstring& value)
    {
        return (0 == StrCmpI(value.c_str(), name_.c_str()));
    }

    std::wstring name_;
};

//-----------------------------------------------------
/** Convenience function to determine if the
    Registry key at hand has the specified
    sub-key

    @precond IsOpen = true

    throws RegistryAccessDenyException
*/
bool RegistryKeyImpl::HasSubKey(const std::wstring& Name) const
{
    StringListPtr names = GetSubKeyNames();

    StringList::iterator iter_end = names->end();
    StringList::iterator iter = std::find_if(names->begin(), iter_end, CompareNamesCaseInsensitive(Name));

    return (iter != iter_end);
}

//-----------------------------------------------------
/**
*/
void RegistryKeyImpl::Close()
{
    if (RegCloseKey(m_hSubKey) != ERROR_SUCCESS) {
        assert(false);
    }

    m_hSubKey = 0;
    m_IsWriteable = false;
}

//-----------------------------------------------------
/** Copies the specified value from RegistryKey to
    the registry key at hand, if a value with this
    name already exist under the registry key at hand
    it will be overwritten

    @precond IsOpen = true
             IsWriteable = true
             RegistryKey.HasSubValue(Name) = true

    @throws RegistryIOException
            RegistryWriteAccessDeniedException
            RegistryValueNotFoundException
*/
void RegistryKeyImpl::CopyValue(const RegistryKey& RegistryKey, const std::wstring& Name)
{
    assert(RegistryKey->HasValue(Name));
#ifdef __MINGW32__
    SetValue((const RegistryValue&)(RegistryKey->GetValue(Name)));
#else
    SetValue(RegistryKey->GetValue(Name));
#endif
    assert(HasValue(Name));
}

/** Copies the specified value from RegistryKey to
    the registry key at hand under a new name,
    if a value with this name already exist there
    it will be overwritten

    @precond IsOpen = true
             IsWriteable = true
             RegistryKey.HasSubValue(Name) = true

    @throws RegistryIOException
            RegistryWriteAccessDeniedException
            RegistryValueNotFoundException
*/
void RegistryKeyImpl::CopyValue(const RegistryKey& RegistryKey, const std::wstring& Name, const std::wstring& NewName)
{
    assert(RegistryKey->HasValue(Name));

    RegistryValue RegVal = RegistryKey->GetValue(Name);
    RegVal->SetName(NewName);
    SetValue(RegVal);

    assert(HasValue(NewName));
}
<|endoftext|>


<commit_before>//===- llvm/unittest/VMCore/Metadata.cpp - Metadata unit tests ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "gtest/gtest.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/MDNode.h"
#include "llvm/Type.h"
#include "llvm/Support/ValueHandle.h"
#include <sstream>

using namespace llvm;

namespace {

// Test that construction of MDString with different value produces different
// MDString objects, even with the same string pointer and nulls in the string.
TEST(MDStringTest, CreateDifferent) {
  char x[3] = { 'f', 0, 'A' };
  MDString *s1 = getGlobalContext().getMDString(StringRef(&x[0], 3));
  x[2] = 'B';
  MDString *s2 = getGlobalContext().getMDString(StringRef(&x[0], 3));
  EXPECT_NE(s1, s2);
}

// Test that creation of MDStrings with the same string contents produces the
// same MDString object, even with different pointers.
TEST(MDStringTest, CreateSame) {
  char x[4] = { 'a', 'b', 'c', 'X' };
  char y[4] = { 'a', 'b', 'c', 'Y' };

  MDString *s1 = getGlobalContext().getMDString(StringRef(&x[0], 3));
  MDString *s2 = getGlobalContext().getMDString(StringRef(&y[0], 3));
  EXPECT_EQ(s1, s2);
}

// Test that MDString prints out the string we fed it.
TEST(MDStringTest, PrintingSimple) {
  char *str = new char[13];
  strncpy(str, "testing 1 2 3", 13);
  MDString *s = getGlobalContext().getMDString(StringRef(str, 13));
  strncpy(str, "aaaaaaaaaaaaa", 13);
  delete[] str;

  std::ostringstream oss;
  s->print(oss);
  EXPECT_STREQ("metadata !\"testing 1 2 3\"", oss.str().c_str());
}

// Test printing of MDString with non-printable characters.
TEST(MDStringTest, PrintingComplex) {
  char str[5] = {0, '\n', '"', '\\', -1};
  MDString *s = getGlobalContext().getMDString(StringRef(str+0, 5));
  std::ostringstream oss;
  s->print(oss);
  EXPECT_STREQ("metadata !\"\\00\\0A\\22\\5C\\FF\"", oss.str().c_str());
}

// Test the two constructors, and containing other Constants.
TEST(MDNodeTest, Simple) {
  char x[3] = { 'a', 'b', 'c' };
  char y[3] = { '1', '2', '3' };

  MDString *s1 = getGlobalContext().getMDString(StringRef(&x[0], 3));
  MDString *s2 = getGlobalContext().getMDString(StringRef(&y[0], 3));
  ConstantInt *CI = ConstantInt::get(getGlobalContext(), APInt(8, 0));

  std::vector<Value *> V;
  V.push_back(s1);
  V.push_back(CI);
  V.push_back(s2);

  MDNode *n1 = getGlobalContext().getMDNode(&V[0], 3);
  Value *const c1 = n1;
  MDNode *n2 = getGlobalContext().getMDNode(&c1, 1);
  MDNode *n3 = getGlobalContext().getMDNode(&V[0], 3);
  EXPECT_NE(n1, n2);
  EXPECT_EQ(n1, n3);

  EXPECT_EQ(3u, n1->getNumElements());
  EXPECT_EQ(s1, n1->getElement(0));
  EXPECT_EQ(CI, n1->getElement(1));
  EXPECT_EQ(s2, n1->getElement(2));

  EXPECT_EQ(1u, n2->getNumElements());
  EXPECT_EQ(n1, n2->getElement(0));

  std::ostringstream oss1, oss2;
  n1->print(oss1);
  n2->print(oss2);
  EXPECT_STREQ("!0 = metadata !{metadata !\"abc\", i8 0, metadata !\"123\"}\n",
               oss1.str().c_str());
  EXPECT_STREQ("!0 = metadata !{metadata !1}\n"
               "!1 = metadata !{metadata !\"abc\", i8 0, metadata !\"123\"}\n",
               oss2.str().c_str());
}

TEST(MDNodeTest, Delete) {
  Constant *C = ConstantInt::get(Type::Int32Ty, 1);
  Instruction *I = new BitCastInst(C, Type::Int32Ty);

  Value *const V = I;
  MDNode *n = getGlobalContext().getMDNode(&V, 1);
  WeakVH wvh = n;

  EXPECT_EQ(n, wvh);

  delete I;

  std::ostringstream oss;
  wvh->print(oss);
  EXPECT_STREQ("!0 = metadata !{null}\n", oss.str().c_str());
}
}
<commit_msg>fix unittest<commit_after>//===- llvm/unittest/VMCore/Metadata.cpp - Metadata unit tests ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "gtest/gtest.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Metadata.h"
#include "llvm/Type.h"
#include "llvm/Support/ValueHandle.h"
#include <sstream>

using namespace llvm;

namespace {

// Test that construction of MDString with different value produces different
// MDString objects, even with the same string pointer and nulls in the string.
TEST(MDStringTest, CreateDifferent) {
  char x[3] = { 'f', 0, 'A' };
  MDString *s1 = getGlobalContext().getMDString(StringRef(&x[0], 3));
  x[2] = 'B';
  MDString *s2 = getGlobalContext().getMDString(StringRef(&x[0], 3));
  EXPECT_NE(s1, s2);
}

// Test that creation of MDStrings with the same string contents produces the
// same MDString object, even with different pointers.
TEST(MDStringTest, CreateSame) {
  char x[4] = { 'a', 'b', 'c', 'X' };
  char y[4] = { 'a', 'b', 'c', 'Y' };

  MDString *s1 = getGlobalContext().getMDString(StringRef(&x[0], 3));
  MDString *s2 = getGlobalContext().getMDString(StringRef(&y[0], 3));
  EXPECT_EQ(s1, s2);
}

// Test that MDString prints out the string we fed it.
TEST(MDStringTest, PrintingSimple) {
  char *str = new char[13];
  strncpy(str, "testing 1 2 3", 13);
  MDString *s = getGlobalContext().getMDString(StringRef(str, 13));
  strncpy(str, "aaaaaaaaaaaaa", 13);
  delete[] str;

  std::ostringstream oss;
  s->print(oss);
  EXPECT_STREQ("metadata !\"testing 1 2 3\"", oss.str().c_str());
}

// Test printing of MDString with non-printable characters.
TEST(MDStringTest, PrintingComplex) {
  char str[5] = {0, '\n', '"', '\\', -1};
  MDString *s = getGlobalContext().getMDString(StringRef(str+0, 5));
  std::ostringstream oss;
  s->print(oss);
  EXPECT_STREQ("metadata !\"\\00\\0A\\22\\5C\\FF\"", oss.str().c_str());
}

// Test the two constructors, and containing other Constants.
TEST(MDNodeTest, Simple) {
  char x[3] = { 'a', 'b', 'c' };
  char y[3] = { '1', '2', '3' };

  MDString *s1 = getGlobalContext().getMDString(StringRef(&x[0], 3));
  MDString *s2 = getGlobalContext().getMDString(StringRef(&y[0], 3));
  ConstantInt *CI = ConstantInt::get(getGlobalContext(), APInt(8, 0));

  std::vector<Value *> V;
  V.push_back(s1);
  V.push_back(CI);
  V.push_back(s2);

  MDNode *n1 = getGlobalContext().getMDNode(&V[0], 3);
  Value *const c1 = n1;
  MDNode *n2 = getGlobalContext().getMDNode(&c1, 1);
  MDNode *n3 = getGlobalContext().getMDNode(&V[0], 3);
  EXPECT_NE(n1, n2);
  EXPECT_EQ(n1, n3);

  EXPECT_EQ(3u, n1->getNumElements());
  EXPECT_EQ(s1, n1->getElement(0));
  EXPECT_EQ(CI, n1->getElement(1));
  EXPECT_EQ(s2, n1->getElement(2));

  EXPECT_EQ(1u, n2->getNumElements());
  EXPECT_EQ(n1, n2->getElement(0));

  std::ostringstream oss1, oss2;
  n1->print(oss1);
  n2->print(oss2);
  EXPECT_STREQ("!0 = metadata !{metadata !\"abc\", i8 0, metadata !\"123\"}\n",
               oss1.str().c_str());
  EXPECT_STREQ("!0 = metadata !{metadata !1}\n"
               "!1 = metadata !{metadata !\"abc\", i8 0, metadata !\"123\"}\n",
               oss2.str().c_str());
}

TEST(MDNodeTest, Delete) {
  Constant *C = ConstantInt::get(Type::Int32Ty, 1);
  Instruction *I = new BitCastInst(C, Type::Int32Ty);

  Value *const V = I;
  MDNode *n = getGlobalContext().getMDNode(&V, 1);
  WeakVH wvh = n;

  EXPECT_EQ(n, wvh);

  delete I;

  std::ostringstream oss;
  wvh->print(oss);
  EXPECT_STREQ("!0 = metadata !{null}\n", oss.str().c_str());
}
}
<|endoftext|>


<commit_before>/*
 *  despot1_main.cpp
 *
 *  Created by Tobias Wood on 23/01/2012.
 *  Copyright 2012 Tobias Wood. All rights reserved.
 *
 */

#include <time.h>
#include <getopt.h>
#include <iostream>
#include <atomic>
#include <Eigen/Dense>
#include <unsupported/Eigen/NonLinearOptimization>

#include "NiftiImage.h"
#include "DESPOT.h"
#include "DESPOT_Functors.h"
#include "RegionContraction.h"

#define USE_PROCPAR
#ifdef USE_PROCPAR
	#include "procpar.h"
	using namespace Recon;
#endif

using namespace std;
using namespace Eigen;

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string credit {
"despot2 - Written by tobias.wood@kcl.ac.uk, based on work by Sean Deoni. \n\
Acknowledgements greatfully received, grant discussions welcome."
};

const string usage {
"Usage is: despot2 [options] output_prefix T1_map ssfp_files\n\
\
Options:\n\
	--help, -h        : Print this message.\n\
	--mask, -m file   : Mask input with specified file.\n\
	--B0 file         : B0 Map file.\n\
	--B1 file         : B1 Map file.\n\
	--M0 file         : Proton density file.\n\
	--verbose, -v     : Print slice processing times.\n\
	--start_slice N   : Start processing from slice N.\n\
	--end_slice   N   : Finish processing at slice N.\n\
	--tesla, -t 3     : Enables DESPOT-FM with boundaries suitable for 3T\n\
	            7     : Boundaries suitable for 7T (default)\n\
	            u     : User specified boundaries from stdin.\n"

};

// tesla == 0 means NO DESPOT-FM
static int tesla = 0, fitB0 = true, verbose = false, start_slice = -1, end_slice = -1;
static string outPrefix;
static struct option long_options[] =
{
	{"B0", required_argument, 0, '0'},
	{"B1", required_argument, 0, '1'},
	{"M0", required_argument, 0, 'M'},
	{"help", no_argument, 0, 'h'},
	{"mask", required_argument, 0, 'm'},
	{"tesla", optional_argument, 0, 'f'},
	{"verbose", no_argument, 0, 'v'},
	{"start_slice", required_argument, 0, 'S'},
	{"end_slice", required_argument, 0, 'E'},
	{0, 0, 0, 0}
};

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv)
{
	//**************************************************************************
	// Argument Processing
	//**************************************************************************
	cout << credit << endl;
	if (argc < 4) {
		cout << usage << endl;
		return EXIT_FAILURE;
	}
	Eigen::initParallel();
	NiftiImage inFile, savedHeader;
	double *maskData = NULL, *B0Data = NULL, *B1Data = NULL, *T1Data = NULL,
	       *M0Data = NULL;
	string procPath;

	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, "hm:vz", long_options, &indexptr)) != -1) {
		switch (c) {
			case 'm':
				cout << "Reading mask file " << optarg << endl;
				inFile.open(optarg, 'r');
				maskData = inFile.readVolume<double>(0);
				inFile.close();
				break;
			case '0':
				cout << "Reading B0 file " << optarg << endl;
				inFile.open(optarg, 'r');
				B0Data = inFile.readVolume<double>(0);
				inFile.close();
				fitB0 = false;
				break;
			case '1':
				cout << "Reading B1 file " << optarg;
				inFile.open(optarg, 'r');
				B1Data = inFile.readVolume<double>(0);
				inFile.close();
				break;
			case 'M':
				cout << "Reading M0 file " << optarg;
				inFile.open(optarg, 'r');
				M0Data = inFile.readVolume<double>(0);
				inFile.close();
				break;
			case 't':
				switch (*optarg) {
					case '3': tesla = 3; break;
					case '7': tesla = 7; break;
					case 'u': tesla = -1; break;
					default:
						cout << "Unknown boundaries type " << optarg << endl;
						abort();
						break;
				}
				cout << "Using " << tesla << "T boundaries." << endl;
				break;
			case 'v':
				verbose = true;
				break;
			case 'S':
				start_slice = atoi(optarg);
				break;
			case 'E':
				end_slice = atoi(optarg);
				break;
			case 0:
				// Just a flag
				break;
			case '?': // getopt will print an error message
			case 'h':
				cout << usage << endl;
				return EXIT_FAILURE;
		}
	}

	cout << "Output prefix will be: " << argv[optind] << endl;
	outPrefix = argv[optind++];
	cout << "Reading T1 Map from: " << argv[optind] << endl;
	inFile.open(argv[optind++], 'r');
	T1Data = inFile.readVolume<double>(0);
	inFile.close();
	savedHeader = inFile;
	//**************************************************************************
	// Gather SSFP Data
	//**************************************************************************
	int nSSFP, nPhases;
	double ssfpTR;
	nPhases = argc - optind;
	vector<double> ssfpPhases(nPhases);
	VectorXd ssfpAngles;
	int voxelsPerSlice, voxelsPerVolume;
	double **ssfpData = (double **)malloc(nPhases * sizeof(double *));
	for (size_t p = 0; p < nPhases; p++)
	{
		cout << "Reading SSFP header from " << argv[optind] << endl;
		inFile.open(argv[optind], 'r');
		if (p == 0)
		{	// Read nSSFP, TR and flip angles from first file
			nSSFP = inFile.dim(4);
			voxelsPerSlice = inFile.voxelsPerSlice();
			voxelsPerVolume = inFile.voxelsPerVolume();
			ssfpAngles.resize(nSSFP, 1);

			#ifdef USE_PROCPAR
			ParameterList pars;
			if (ReadProcpar(inFile.basename() + ".procpar", pars)) {
				ssfpTR = RealValue(pars, "tr");
				for (int i = 0; i < nSSFP; i++)
					ssfpAngles[i] = RealValue(pars, "flip1", i);
			} else
			#endif
			{
				cout << "Enter SSFP TR (s): " << flush;
				cin >> ssfpTR;
				cout << "Enter " << nSSFP << " flip angles (degrees): " << flush;
				for (int i = 0; i < ssfpAngles.size(); i++)
					cin >> ssfpAngles[i];
			}
		}
		#ifdef USE_PROCPAR
		ParameterList pars;
		if (ReadProcpar(inFile.basename() + ".procpar", pars)) {
			ssfpPhases[p] = RealValue(pars, "rfphase") * M_PI / 180.;
		} else
		#endif
		{
			cout << "Enter phase-cycling (degrees): " << flush;
			cin >> ssfpPhases[p]; ssfpPhases[p] *= M_PI / 180.;
		}
		cout << "Reading SSFP data..." << endl;
		ssfpData[p] = inFile.readAllVolumes<double>();
		// Don't close the first header because we've saved it to write the
		// results, and FSLIO gets fussy about cloning closed headers
		inFile.close();
		optind++;
	}
	ssfpAngles *= M_PI / 180.;

	if (optind != argc) {
		cerr << "Unprocessed arguments supplied.\n" << usage;
		exit(EXIT_FAILURE);
	}

	// Set up boundaries for DESPOT-FM if needed
	DESPOT2FM::ParamType loBounds, hiBounds;
	if (tesla != 0) {
		if (tesla > 0) {
			loBounds = DESPOT2FM::loBounds(tesla);
			hiBounds = DESPOT2FM::hiBounds(tesla);
		} else if (tesla < 0) {
			cout << "Enter " << DESPOT2FM::nP << " parameter pairs (low then high): " << flush;
			for (int i = 0; i < DESPOT2FM::nP; i++) cin >> loBounds[i] >> hiBounds[i];
		}
		// If fitting, give a suitable range and allocate results memory
		if (fitB0) {
			loBounds[DESPOT2FM::nP - 1] = -0.5 / ssfpTR;
			hiBounds[DESPOT2FM::nP - 1] =  0.5 / ssfpTR;
			B0Data = new double[voxelsPerVolume];
		} else { // Otherwise fix and let functors pick up the specified value
			loBounds[DESPOT2FM::nP - 1] = 0.;
			hiBounds[DESPOT2FM::nP - 1] = 0.;
		}
	}

	if (verbose) {
		cout << "SSFP Angles (deg): " << ssfpAngles.transpose() * 180 / M_PI << endl;
		if (tesla != 0)
			cout << "Low bounds: " << loBounds.transpose() << endl
				 << "Hi bounds:  " << hiBounds.transpose() << endl;
	}
	//**************************************************************************
	// Set up results data
	//**************************************************************************
	double *residualData = new double[voxelsPerVolume];
	double *PDData = new double[voxelsPerVolume];
	double *T2Data = new double[voxelsPerVolume];
	//**************************************************************************
	// Do the fitting
	//**************************************************************************
    time_t procStart = time(NULL);
	if ((start_slice < 0) || (start_slice >= inFile.dim(4)))
		start_slice = 0;
	if ((end_slice < 0) || (end_slice > inFile.dim(4)))
		end_slice = inFile.dim(4);
	for (int slice = start_slice; slice < end_slice; slice++) {
		// Read in data
		if (verbose)
			cout << "Starting slice " << slice << "..." << flush;

		atomic<int> voxCount{0};
		const int sliceOffset = slice * voxelsPerSlice;
		clock_t loopStart = clock();
		function<void (const int&)> processVox = [&] (const int &vox) {
			// Set up parameters and constants
			double M0 = 0., T1 = 0., T2 = 0., B0 = 0, B1 = 1., residual = 0.;
			if (!maskData || ((maskData[sliceOffset + vox] > 0.) && (T1Data[sliceOffset + vox] > 0.)))
			{	// Zero T1 causes zero-pivot error.
				voxCount++;
				T1 = T1Data[sliceOffset + vox];
				if (B0Data) B0 = B0Data[sliceOffset + vox];
				if (B1Data)	B1 = B1Data[sliceOffset + vox];
				// Gather signals.
				vector<VectorXd> signals;
				for (int p = 0; p < nPhases; p++)
				{
					VectorXd temp(nSSFP);
					for (int i = 0; i < nSSFP; i++)
						temp(i) = ssfpData[p][i*voxelsPerVolume + sliceOffset + vox];
					signals.push_back(temp);
				}

				if (tesla == 0) {
					// Choose phase with accumulated phase closest to 180 and then classic DESPOT2
					int index = 0;
					double bestPhase = DBL_MAX;
					for (int p = 0; p < nPhases; p++) {
						double thisPhase = (B0 * ssfpTR * 2 * M_PI) + ssfpPhases[p];
						if (fabs(fmod(thisPhase - M_PI, 2 * M_PI)) < bestPhase) {
							bestPhase = fabs(fmod(thisPhase - M_PI, 2 * M_PI));
							index = p;
						}
					}
					residual = classicDESPOT2(ssfpAngles, signals[index], ssfpTR, T1, B1, M0, T2);
				} else {
					// DESPOT2-FM
					VectorXd allB0(nSSFP), allB1(nSSFP);
					allB0.setConstant(B0);
					allB1.setConstant(B1);
					DESPOT2FM tc(ssfpAngles, ssfpPhases, signals,
				                 allB0, allB1, ssfpTR, false, fitB0);
					DESPOT2FM::ParamType params(DESPOT2FM::nP);
					residual = regionContraction<DESPOT2FM>(params, tc, loBounds, hiBounds);
					M0 = params[0];
					T2 = params[1];
					if (fitB0)
						B0 = params[2];

				}
			}
			PDData[sliceOffset + vox] = clamp(M0, 0., 5.e3);
			T2Data[sliceOffset + vox] = clamp(T2, 0., 0.5);
			if (fitB0)
				B0Data[sliceOffset + vox] = B0;
			residualData[sliceOffset + vox] = residual;
		};
		apply_for(voxelsPerSlice, processVox);

		if (verbose) {
			clock_t loopEnd = clock();
			if (voxCount > 0)
				cout << voxCount << " unmasked voxels, CPU time per voxel was "
				          << ((loopEnd - loopStart) / ((float)voxCount * CLOCKS_PER_SEC)) << " s, ";
			cout << "finished." << endl;
		}
	}
    time_t procEnd = time(NULL);
    struct tm *localEnd = localtime(&procEnd);
	char theTime[512];
    strftime(theTime, 512, "%H:%M:%S", localEnd);
	cout << "Finished processing at " << theTime << ". Run-time was "
	          << difftime(procEnd, procStart) << " s." << endl;
	savedHeader.setDim(4, 1);
	savedHeader.setDatatype(NIFTI_TYPE_FLOAT32);
	savedHeader.open(outPrefix + "_T2.nii.gz", NiftiImage::NIFTI_WRITE);
	savedHeader.writeVolume(0, T2Data);
	savedHeader.close();
	savedHeader.open(outPrefix + "_PD.nii.gz", NiftiImage::NIFTI_WRITE);
	savedHeader.writeVolume(0, PDData);
	savedHeader.close();
	if (fitB0) {
		savedHeader.open(outPrefix + "_B0.nii.gz", NiftiImage::NIFTI_WRITE);
		savedHeader.writeVolume(0, B0Data);
		savedHeader.close();
	}
	// Clean up memory
	for (int p = 0; p < nPhases; p++)
		free(ssfpData[p]);
	if (B0Data)
		free(B0Data);
	if (B1Data)
		free(B1Data);
	if (maskData)
		free(maskData);
	return EXIT_SUCCESS;
}
<commit_msg>Fixed bug in logic for whether fitting B0 is required. Changed 'nSSFP' to 'nFlip', it's a better variable name.<commit_after>/*
 *  despot1_main.cpp
 *
 *  Created by Tobias Wood on 23/01/2012.
 *  Copyright 2012 Tobias Wood. All rights reserved.
 *
 */

#include <time.h>
#include <getopt.h>
#include <iostream>
#include <atomic>
#include <Eigen/Dense>
#include <unsupported/Eigen/NonLinearOptimization>

#include "NiftiImage.h"
#include "DESPOT.h"
#include "DESPOT_Functors.h"
#include "RegionContraction.h"

#define USE_PROCPAR
#ifdef USE_PROCPAR
	#include "procpar.h"
	using namespace Recon;
#endif

using namespace std;
using namespace Eigen;

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string credit {
"despot2 - Written by tobias.wood@kcl.ac.uk, based on work by Sean Deoni. \n\
Acknowledgements greatfully received, grant discussions welcome."
};

const string usage {
"Usage is: despot2 [options] output_prefix T1_map ssfp_files\n\
\
Options:\n\
	--help, -h        : Print this message.\n\
	--mask, -m file   : Mask input with specified file.\n\
	--B0 file         : B0 Map file.\n\
	--B1 file         : B1 Map file.\n\
	--M0 file         : Proton density file.\n\
	--verbose, -v     : Print slice processing times.\n\
	--start_slice N   : Start processing from slice N.\n\
	--end_slice   N   : Finish processing at slice N.\n\
	--tesla, -t 3     : Enables DESPOT-FM with boundaries suitable for 3T\n\
	            7     : Boundaries suitable for 7T (default)\n\
	            u     : User specified boundaries from stdin.\n"

};

// tesla == 0 means NO DESPOT-FM
static int tesla = 0, fitB0 = false, verbose = false, start_slice = -1, end_slice = -1;
static string outPrefix;
static struct option long_options[] =
{
	{"B0", required_argument, 0, '0'},
	{"B1", required_argument, 0, '1'},
	{"M0", required_argument, 0, 'M'},
	{"help", no_argument, 0, 'h'},
	{"mask", required_argument, 0, 'm'},
	{"tesla", optional_argument, 0, 'f'},
	{"verbose", no_argument, 0, 'v'},
	{"start_slice", required_argument, 0, 'S'},
	{"end_slice", required_argument, 0, 'E'},
	{0, 0, 0, 0}
};

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv)
{
	//**************************************************************************
	// Argument Processing
	//**************************************************************************
	cout << credit << endl;
	if (argc < 4) {
		cout << usage << endl;
		return EXIT_FAILURE;
	}
	Eigen::initParallel();
	NiftiImage inFile, savedHeader;
	double *maskData = NULL, *B0Data = NULL, *B1Data = NULL, *T1Data = NULL,
	       *M0Data = NULL;
	string procPath;

	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, "hm:vz", long_options, &indexptr)) != -1) {
		switch (c) {
			case 'm':
				cout << "Reading mask file " << optarg << endl;
				inFile.open(optarg, 'r');
				maskData = inFile.readVolume<double>(0);
				inFile.close();
				break;
			case '0':
				cout << "Reading B0 file " << optarg << endl;
				inFile.open(optarg, 'r');
				B0Data = inFile.readVolume<double>(0);
				inFile.close();
				break;
			case '1':
				cout << "Reading B1 file " << optarg;
				inFile.open(optarg, 'r');
				B1Data = inFile.readVolume<double>(0);
				inFile.close();
				break;
			case 'M':
				cout << "Reading M0 file " << optarg;
				inFile.open(optarg, 'r');
				M0Data = inFile.readVolume<double>(0);
				inFile.close();
				break;
			case 't':
				switch (*optarg) {
					case '3': tesla = 3; break;
					case '7': tesla = 7; break;
					case 'u': tesla = -1; break;
					default:
						cout << "Unknown boundaries type " << optarg << endl;
						abort();
						break;
				}
				cout << "Using " << tesla << "T boundaries." << endl;
				break;
			case 'v':
				verbose = true;
				break;
			case 'S':
				start_slice = atoi(optarg);
				break;
			case 'E':
				end_slice = atoi(optarg);
				break;
			case 0:
				// Just a flag
				break;
			case '?': // getopt will print an error message
			case 'h':
				cout << usage << endl;
				return EXIT_FAILURE;
		}
	}
	if ((tesla != 0) && !B0Data)
		fitB0 = true;
	cout << "Output prefix will be: " << argv[optind] << endl;
	outPrefix = argv[optind++];
	cout << "Reading T1 Map from: " << argv[optind] << endl;
	inFile.open(argv[optind++], 'r');
	T1Data = inFile.readVolume<double>(0);
	inFile.close();
	savedHeader = inFile;
	//**************************************************************************
	// Gather SSFP Data
	//**************************************************************************
	int nFlip, nPhases;
	double ssfpTR;
	nPhases = argc - optind;
	vector<double> ssfpPhases(nPhases);
	VectorXd ssfpAngles;
	int voxelsPerSlice, voxelsPerVolume;
	double **ssfpData = (double **)malloc(nPhases * sizeof(double *));
	for (size_t p = 0; p < nPhases; p++)
	{
		cout << "Reading SSFP header from " << argv[optind] << endl;
		inFile.open(argv[optind], 'r');
		if (p == 0)
		{	// Read nFlip, TR and flip angles from first file
			nFlip = inFile.dim(4);
			voxelsPerSlice = inFile.voxelsPerSlice();
			voxelsPerVolume = inFile.voxelsPerVolume();
			ssfpAngles.resize(nFlip, 1);

			#ifdef USE_PROCPAR
			ParameterList pars;
			if (ReadProcpar(inFile.basename() + ".procpar", pars)) {
				ssfpTR = RealValue(pars, "tr");
				for (int i = 0; i < nFlip; i++)
					ssfpAngles[i] = RealValue(pars, "flip1", i);
			} else
			#endif
			{
				cout << "Enter SSFP TR (s): " << flush;
				cin >> ssfpTR;
				cout << "Enter " << nFlip << " flip angles (degrees): " << flush;
				for (int i = 0; i < ssfpAngles.size(); i++)
					cin >> ssfpAngles[i];
			}
		}
		#ifdef USE_PROCPAR
		ParameterList pars;
		if (ReadProcpar(inFile.basename() + ".procpar", pars)) {
			ssfpPhases[p] = RealValue(pars, "rfphase") * M_PI / 180.;
		} else
		#endif
		{
			cout << "Enter phase-cycling (degrees): " << flush;
			cin >> ssfpPhases[p]; ssfpPhases[p] *= M_PI / 180.;
		}
		cout << "Reading SSFP data..." << endl;
		ssfpData[p] = inFile.readAllVolumes<double>();
		// Don't close the first header because we've saved it to write the
		// results, and FSLIO gets fussy about cloning closed headers
		inFile.close();
		optind++;
	}
	ssfpAngles *= M_PI / 180.;

	if (optind != argc) {
		cerr << "Unprocessed arguments supplied.\n" << usage;
		exit(EXIT_FAILURE);
	}

	// Set up boundaries for DESPOT-FM if needed
	DESPOT2FM::ParamType loBounds, hiBounds;
	if (tesla != 0) {
		if (tesla > 0) {
			loBounds = DESPOT2FM::loBounds(tesla);
			hiBounds = DESPOT2FM::hiBounds(tesla);
		} else if (tesla < 0) {
			cout << "Enter " << DESPOT2FM::nP << " parameter pairs (low then high): " << flush;
			for (int i = 0; i < DESPOT2FM::nP; i++) cin >> loBounds[i] >> hiBounds[i];
		}
		// If fitting, give a suitable range and allocate results memory
		if (fitB0) {
			loBounds[DESPOT2FM::nP - 1] = -0.5 / ssfpTR;
			hiBounds[DESPOT2FM::nP - 1] =  0.5 / ssfpTR;
			B0Data = new double[voxelsPerVolume];
		} else { // Otherwise fix and let functors pick up the specified value
			loBounds[DESPOT2FM::nP - 1] = 0.;
			hiBounds[DESPOT2FM::nP - 1] = 0.;
		}
	}

	if (verbose) {
		cout << "SSFP Angles (deg): " << ssfpAngles.transpose() * 180 / M_PI << endl;
		if (tesla != 0)
			cout << "Low bounds: " << loBounds.transpose() << endl
				 << "Hi bounds:  " << hiBounds.transpose() << endl;
	}
	//**************************************************************************
	// Set up results data
	//**************************************************************************
	double *residualData = new double[voxelsPerVolume];
	double *PDData = new double[voxelsPerVolume];
	double *T2Data = new double[voxelsPerVolume];
	//**************************************************************************
	// Do the fitting
	//**************************************************************************
    time_t procStart = time(NULL);
	if ((start_slice < 0) || (start_slice >= inFile.dim(4)))
		start_slice = 0;
	if ((end_slice < 0) || (end_slice > inFile.dim(4)))
		end_slice = inFile.dim(4);
	for (int slice = start_slice; slice < end_slice; slice++) {
		// Read in data
		if (verbose)
			cout << "Starting slice " << slice << "..." << flush;

		atomic<int> voxCount{0};
		const int sliceOffset = slice * voxelsPerSlice;
		clock_t loopStart = clock();
		function<void (const int&)> processVox = [&] (const int &vox) {
			// Set up parameters and constants
			double M0 = 0., T1 = 0., T2 = 0., B0 = 0, B1 = 1., residual = 0.;
			if (!maskData || ((maskData[sliceOffset + vox] > 0.) && (T1Data[sliceOffset + vox] > 0.)))
			{	// Zero T1 causes zero-pivot error.
				voxCount++;
				T1 = T1Data[sliceOffset + vox];
				if (B0Data) B0 = B0Data[sliceOffset + vox];
				if (B1Data)	B1 = B1Data[sliceOffset + vox];
				// Gather signals.
				vector<VectorXd> signals;
				for (int p = 0; p < nPhases; p++)
				{
					VectorXd temp(nFlip);
					for (int i = 0; i < nFlip; i++)
						temp(i) = ssfpData[p][i*voxelsPerVolume + sliceOffset + vox];
					signals.push_back(temp);
				}

				if (tesla == 0) {
					// Choose phase with accumulated phase closest to 180 and then classic DESPOT2
					int index = 0;
					double bestPhase = DBL_MAX;
					for (int p = 0; p < nPhases; p++) {
						double thisPhase = (B0 * ssfpTR * 2 * M_PI) + ssfpPhases[p];
						if (fabs(fmod(thisPhase - M_PI, 2 * M_PI)) < bestPhase) {
							bestPhase = fabs(fmod(thisPhase - M_PI, 2 * M_PI));
							index = p;
						}
					}
					residual = classicDESPOT2(ssfpAngles, signals[index], ssfpTR, T1, B1, M0, T2);
				} else {
					// DESPOT2-FM
					VectorXd allB0(nFlip), allB1(nFlip);
					allB0.setConstant(B0);
					allB1.setConstant(B1);
					DESPOT2FM tc(ssfpAngles, ssfpPhases, signals,
				                 allB0, allB1, ssfpTR, false, fitB0);
					DESPOT2FM::ParamType params(DESPOT2FM::nP);
					residual = regionContraction<DESPOT2FM>(params, tc, loBounds, hiBounds);
					M0 = params[0];
					T2 = params[1];
					if (fitB0)
						B0 = params[2];

				}
			}
			PDData[sliceOffset + vox] = clamp(M0, 0., 5.e3);
			T2Data[sliceOffset + vox] = clamp(T2, 0., 0.5);
			if (fitB0)
				B0Data[sliceOffset + vox] = B0;
			residualData[sliceOffset + vox] = residual;
		};
		apply_for(voxelsPerSlice, processVox);

		if (verbose) {
			clock_t loopEnd = clock();
			if (voxCount > 0)
				cout << voxCount << " unmasked voxels, CPU time per voxel was "
				          << ((loopEnd - loopStart) / ((float)voxCount * CLOCKS_PER_SEC)) << " s, ";
			cout << "finished." << endl;
		}
	}
    time_t procEnd = time(NULL);
    struct tm *localEnd = localtime(&procEnd);
	char theTime[512];
    strftime(theTime, 512, "%H:%M:%S", localEnd);
	cout << "Finished processing at " << theTime << ". Run-time was "
	          << difftime(procEnd, procStart) << " s." << endl;
	savedHeader.setDim(4, 1);
	savedHeader.setDatatype(NIFTI_TYPE_FLOAT32);
	savedHeader.open(outPrefix + "_T2.nii.gz", NiftiImage::NIFTI_WRITE);
	savedHeader.writeVolume(0, T2Data);
	savedHeader.close();
	savedHeader.open(outPrefix + "_PD.nii.gz", NiftiImage::NIFTI_WRITE);
	savedHeader.writeVolume(0, PDData);
	savedHeader.close();
	if (fitB0) {
		savedHeader.open(outPrefix + "_B0.nii.gz", NiftiImage::NIFTI_WRITE);
		savedHeader.writeVolume(0, B0Data);
		savedHeader.close();
	}
	// Clean up memory
	for (int p = 0; p < nPhases; p++)
		free(ssfpData[p]);
	if (B0Data)
		free(B0Data);
	if (B1Data)
		free(B1Data);
	if (maskData)
		free(maskData);
	return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include <iostream>

#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>

#include "dafs/constants.hpp"
#include "dafs/dispatcher.hpp"
#include "dafs/dafs-server.hpp"
#include "dafs/node.hpp"
#include "dafs/sender.hpp"
#include "dafs/server.hpp"

void
CreateReplicatedFile(
    std::string directory,
    std::string filename,
    std::string content)
{
    boost::filesystem::path replicated_file(directory);
    replicated_file /= filename;
    std::fstream replicated_file_stream(
        replicated_file.string(),
        std::ios::in | std::ios::out | std::ios::trunc);
    replicated_file_stream << content << std::endl;
}

void
SetupReplicatedFiles(
    std::string directory,
    dafs::Address management_interface,
    dafs::Address replication_interface,
    dafs::Identity identity)
{
    if (!boost::filesystem::exists(directory))
    {
        boost::filesystem::create_directory(directory);

        // write out replicaset file
        CreateReplicatedFile(
            directory,
            ReplicasetFilename,
            replication_interface.ip + ":" + std::to_string(
                replication_interface.port)
        );

        // write out identity file
        CreateReplicatedFile(
            directory,
            Constant::IdentityFilename,
            dafs::Serialize(identity)
        );

        // write out author file
        CreateReplicatedFile(
            directory,
            Constant::AuthorFilename,
            dafs::Serialize(management_interface)
        );
    }
}

std::shared_ptr<dafs::ReplicatedPartition>
SetupPartition(
    std::string directory,
    dafs::Address management_interface,
    dafs::Address replication_interface,
    dafs::Identity identity)
{
    SetupReplicatedFiles(
        directory,
        management_interface,
        replication_interface,
        identity);

    return std::make_shared<dafs::ReplicatedPartition>(
        replication_interface,
        dafs::Root(directory));
}

void
SetupNode(std::string settings_file)
{
    //[partition-minus]
    //port = 8070
    //
    //[partition-zero]
    //port = 8080
    //
    //[partition-plus]
    //port = 8090
    // write out node config file
    std::fstream config(settings_file, std::ios::out | std::ios::trunc);
    config << "[partition-minus]" << std::endl;
    config << "port = 8070" << std::endl;
    config << "" << std::endl;

    config << "[partition-zero]" << std::endl;
    config << "port = 8080" << std::endl;
    config << "" << std::endl;

    config << "[partition-plus]" << std::endl;
    config << "port = 8090" << std::endl;
}

int main(int argc, char** argv)
{
    Options options;

    //
    // Parse the command line options.
    //
    boost::program_options::options_description desc("Allowed options");
    desc.add_options()
        ("help", "produce help message")
        ("identity",
         boost::program_options::value(&options.identity),
         "uuid identity of the node")
        ("address",
         boost::program_options::value(&options.address)->default_value("127.0.0.1"),
         "address of the node")
        ("port",
         boost::program_options::value(&options.port)->default_value(9000),
         "port of the node")
        ("config",
         boost::program_options::value(&options.settings_file)->default_value("config.ini"),
         "node configuration file")
    ;
    boost::program_options::variables_map cli_vm;
    boost::program_options::store(
        boost::program_options::parse_command_line(argc, argv, desc),
        cli_vm);
    boost::program_options::notify(cli_vm);

    if (cli_vm.count("help"))
    {
        std::cout << desc << "\n";
        std::exit(EXIT_FAILURE);
    }

    //
    // Parse the configuration file.
    //
    boost::program_options::options_description desc_settings("Configuration options");
    desc_settings.add_options()
        ("partition-minus.port",
         boost::program_options::value(&options.minus_port),
         "port of the minus partition")
        ("partition-zero.port",
         boost::program_options::value(&options.zero_port),
         "port of the zero partition")
        ("partition-plus.port",
         boost::program_options::value(&options.plus_port),
         "port of the plus partition")
    ;

    std::ifstream config(options.settings_file);
    boost::program_options::variables_map config_vm;
    boost::program_options::store(
        boost::program_options::parse_config_file<char>(
            options.settings_file.c_str(),
            desc_settings),
        config_vm);
    boost::program_options::notify(config_vm);

    //
    // Setup the partitions
    //
    auto pminus = SetupPartition(
        Constant::PartitionMinusName,
        dafs::EmptyAddress(),
        dafs::Address(options.address, options.minus_port),
        dafs::Identity(boost::uuids::to_string(options.identity)) -
        dafs::Identity("00000000-0000-0000-0000-0000000000ff")
    );
    auto pzero = SetupPartition(
        Constant::PartitionZeroName,
        dafs::Address(options.address, options.port),
        dafs::Address(options.address, options.zero_port),
        dafs::Identity(boost::uuids::to_string(options.identity))
    );
    auto pplus = SetupPartition(
        Constant::PartitionPlusName,
        dafs::EmptyAddress(),
        dafs::Address(options.address, options.plus_port),
        dafs::Identity(boost::uuids::to_string(options.identity)) +
        dafs::Identity("00000000-0000-0000-0000-0000000000ff")
    );

    //
    // Start node and server.
    //
    dafs::Node n(pminus, pzero, pplus);
    dafs::Dispatcher dispatcher(n);

    auto server = boost::make_shared<dafs::Server>(
        options.address,
        options.port,
        dispatcher);

    server->Start();

    for (;;);
}
<commit_msg>Replace hard spin wait with future wait<commit_after>#include <iostream>
#include <future>

#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>

#include "dafs/constants.hpp"
#include "dafs/dispatcher.hpp"
#include "dafs/dafs-server.hpp"
#include "dafs/node.hpp"
#include "dafs/sender.hpp"
#include "dafs/server.hpp"

void
CreateReplicatedFile(
    std::string directory,
    std::string filename,
    std::string content)
{
    boost::filesystem::path replicated_file(directory);
    replicated_file /= filename;
    std::fstream replicated_file_stream(
        replicated_file.string(),
        std::ios::in | std::ios::out | std::ios::trunc);
    replicated_file_stream << content << std::endl;
}

void
SetupReplicatedFiles(
    std::string directory,
    dafs::Address management_interface,
    dafs::Address replication_interface,
    dafs::Identity identity)
{
    if (!boost::filesystem::exists(directory))
    {
        boost::filesystem::create_directory(directory);

        // write out replicaset file
        CreateReplicatedFile(
            directory,
            ReplicasetFilename,
            replication_interface.ip + ":" + std::to_string(
                replication_interface.port)
        );

        // write out identity file
        CreateReplicatedFile(
            directory,
            Constant::IdentityFilename,
            dafs::Serialize(identity)
        );

        // write out author file
        CreateReplicatedFile(
            directory,
            Constant::AuthorFilename,
            dafs::Serialize(management_interface)
        );
    }
}

std::shared_ptr<dafs::ReplicatedPartition>
SetupPartition(
    std::string directory,
    dafs::Address management_interface,
    dafs::Address replication_interface,
    dafs::Identity identity)
{
    SetupReplicatedFiles(
        directory,
        management_interface,
        replication_interface,
        identity);

    return std::make_shared<dafs::ReplicatedPartition>(
        replication_interface,
        dafs::Root(directory));
}

void
SetupNode(std::string settings_file)
{
    //[partition-minus]
    //port = 8070
    //
    //[partition-zero]
    //port = 8080
    //
    //[partition-plus]
    //port = 8090
    // write out node config file
    std::fstream config(settings_file, std::ios::out | std::ios::trunc);
    config << "[partition-minus]" << std::endl;
    config << "port = 8070" << std::endl;
    config << "" << std::endl;

    config << "[partition-zero]" << std::endl;
    config << "port = 8080" << std::endl;
    config << "" << std::endl;

    config << "[partition-plus]" << std::endl;
    config << "port = 8090" << std::endl;
}

int main(int argc, char** argv)
{
    Options options;

    //
    // Parse the command line options.
    //
    boost::program_options::options_description desc("Allowed options");
    desc.add_options()
        ("help", "produce help message")
        ("identity",
         boost::program_options::value(&options.identity),
         "uuid identity of the node")
        ("address",
         boost::program_options::value(&options.address)->default_value("127.0.0.1"),
         "address of the node")
        ("port",
         boost::program_options::value(&options.port)->default_value(9000),
         "port of the node")
        ("config",
         boost::program_options::value(&options.settings_file)->default_value("config.ini"),
         "node configuration file")
    ;
    boost::program_options::variables_map cli_vm;
    boost::program_options::store(
        boost::program_options::parse_command_line(argc, argv, desc),
        cli_vm);
    boost::program_options::notify(cli_vm);

    if (cli_vm.count("help"))
    {
        std::cout << desc << "\n";
        std::exit(EXIT_FAILURE);
    }

    //
    // Parse the configuration file.
    //
    boost::program_options::options_description desc_settings("Configuration options");
    desc_settings.add_options()
        ("partition-minus.port",
         boost::program_options::value(&options.minus_port),
         "port of the minus partition")
        ("partition-zero.port",
         boost::program_options::value(&options.zero_port),
         "port of the zero partition")
        ("partition-plus.port",
         boost::program_options::value(&options.plus_port),
         "port of the plus partition")
    ;

    std::ifstream config(options.settings_file);
    boost::program_options::variables_map config_vm;
    boost::program_options::store(
        boost::program_options::parse_config_file<char>(
            options.settings_file.c_str(),
            desc_settings),
        config_vm);
    boost::program_options::notify(config_vm);

    //
    // Setup the partitions
    //
    auto pminus = SetupPartition(
        Constant::PartitionMinusName,
        dafs::EmptyAddress(),
        dafs::Address(options.address, options.minus_port),
        dafs::Identity(boost::uuids::to_string(options.identity)) -
        dafs::Identity("00000000-0000-0000-0000-0000000000ff")
    );
    auto pzero = SetupPartition(
        Constant::PartitionZeroName,
        dafs::Address(options.address, options.port),
        dafs::Address(options.address, options.zero_port),
        dafs::Identity(boost::uuids::to_string(options.identity))
    );
    auto pplus = SetupPartition(
        Constant::PartitionPlusName,
        dafs::EmptyAddress(),
        dafs::Address(options.address, options.plus_port),
        dafs::Identity(boost::uuids::to_string(options.identity)) +
        dafs::Identity("00000000-0000-0000-0000-0000000000ff")
    );

    //
    // Start node and server.
    //
    dafs::Node n(pminus, pzero, pplus);
    dafs::Dispatcher dispatcher(n);

    auto server = boost::make_shared<dafs::Server>(
        options.address,
        options.port,
        dispatcher);

    server->Start();
    std::promise<void>().get_future().wait();
}
<|endoftext|>


<commit_before>#include <sys/sendfile.h>

#include <cerrno>
#include <algorithm>
#include <limits>

#include "direct-fd-stream.hh"
#include "copy.hh"

namespace mimosa
{
  namespace stream
  {
    DirectFdStream::DirectFdStream(int fd, bool own_fd)
      : fd_(fd),
        own_fd_(own_fd),
        mode_(0)
    {
    }

    DirectFdStream::~DirectFdStream()
    {
      if (own_fd_ && fd_ >= 0)
      {
        ::close(fd_);
        fd_ = -1;
      }
    }

    int64_t
    DirectFdStream::write(const char * data, uint64_t nbytes)
    {
      return ::write(fd_, data, nbytes);
    }

    int64_t
    DirectFdStream::writev(const struct iovec *iov, int iovcnt)
    {
      return ::writev(fd_, iov, iovcnt < IOV_MAX ? iovcnt : IOV_MAX);
    }

    int64_t
    DirectFdStream::read(char * data, uint64_t nbytes)
    {
      return ::read(fd_, data, nbytes);
    }

    int64_t
    DirectFdStream::readv(const struct iovec *iov, int iovcnt)
    {
      return ::readv(fd_, iov, iovcnt < IOV_MAX ? iovcnt : IOV_MAX);
    }

    void
    DirectFdStream::close()
    {
      assert(own_fd_);
      if (own_fd_ && fd_ >= 0)
      {
        int fd = fd_;
        fd_    = -1;
        ::close(fd);
      }
    }

    bool
    DirectFdStream::stat() const
    {
      struct ::stat st;
      if (::fstat(fd_, &st))
        return false;
      mode_ = st.st_mode;
      return true;
    }

    static int64_t copySendfile(DirectFdStream & input,
                                DirectFdStream & output,
                                int64_t          max_bytes)
    {
      int64_t total = 0;

      while (total < max_bytes || max_bytes == 0) {
        int64_t limit;

        if (max_bytes == 0)
          limit = std::numeric_limits<int64_t>::max();
        else
          limit = max_bytes - total;

        ssize_t bytes = ::sendfile(output.fd(), input.fd(), nullptr, limit);
        if (bytes <= 0) {
          if (errno == EAGAIN)
            continue;
          return total;
        }
        total += bytes;
      }
      return total;
    }

    static int64_t copySplice(DirectFdStream & input,
                              DirectFdStream & output,
                              int64_t          max_bytes)
    {
      int64_t total = 0;

      while (total < max_bytes || max_bytes == 0) {
        int64_t limit;

        if (max_bytes == 0)
          limit = std::numeric_limits<int64_t>::max();
        else
          limit = max_bytes - total;

        ssize_t bytes = ::splice(input.fd(), nullptr, output.fd(), nullptr, limit, 0);
        if (bytes <= 0) {
          if (errno == EAGAIN)
            continue;
          return total;
        }
        total += bytes;
      }
      return total;
    }

#if 0
    static int64_t copySpliceAny(DirectFdStream & input,
                                 DirectFdStream & output,
                                 int64_t          max_bytes)
    {
      int     pfd[2];
      int64_t total = 0;

      if (::pipe2(pfd, O_CLOEXEC | O_NONBLOCK))
        return -1;

      while (total < max_bytes || max_bytes == 0) {
        int64_t limit;

        if (max_bytes == 0)
          limit = std::numeric_limits<int64_t>::max();
        else
          limit = max_bytes - total;

        ssize_t rbytes = ::splice(input.fd(), nullptr, pfd[1], nullptr, limit, 0);
        if (bytes <= 0) {
          if (errno == EAGAIN)
            continue;
          goto end;
        }

        while (rbytes > 0) {
          ssize_t wbytes = ::splice(pfd[0], nullptr, output.fd(), nullptr, rbytes, 0);
          if (wbytes < 0) {
            if (errno == EAGAIN)
              continue;
            total = -1;
            goto end;
          }

          total  += wbytes;
          rbytes -= wbytes;
        }
      }

      end:
      ::close(pfd[0]);
      ::close(pfd[1]);
      return total;
    }
#endif

    int64_t copy(DirectFdStream & input,
                 DirectFdStream & output,
                 int64_t          max_bytes)
    {
      // disk to fd
      if (S_ISREG(input.fdMode()))
        return copySendfile(input, output, max_bytes);

      // from a pipe or to a pipe
      if (S_ISFIFO(input.fdMode()) || S_ISFIFO(output.fdMode()))
        return copySplice(input, output, max_bytes);

#if 0
      // splice: input -> pipe -> output
      if (max_bytes == 0 || max_bytes > 4096)
        return copySpliceAny(input, output, max_bytes);
#endif

      // user copy
      return copy(static_cast<Stream &> (input),
                  static_cast<Stream &> (output),
                  max_bytes);
    }
  }
}
<commit_msg>DirectFdStream: splice and sendfile code is linux specific<commit_after>#ifdef __linux__
# include <sys/sendfile.h>
#endif

#include <cerrno>
#include <algorithm>
#include <limits>

#include "direct-fd-stream.hh"
#include "copy.hh"

namespace mimosa
{
  namespace stream
  {
    DirectFdStream::DirectFdStream(int fd, bool own_fd)
      : fd_(fd),
        own_fd_(own_fd),
        mode_(0)
    {
    }

    DirectFdStream::~DirectFdStream()
    {
      if (own_fd_ && fd_ >= 0)
      {
        ::close(fd_);
        fd_ = -1;
      }
    }

    int64_t
    DirectFdStream::write(const char * data, uint64_t nbytes)
    {
      return ::write(fd_, data, nbytes);
    }

    int64_t
    DirectFdStream::writev(const struct iovec *iov, int iovcnt)
    {
      return ::writev(fd_, iov, iovcnt < IOV_MAX ? iovcnt : IOV_MAX);
    }

    int64_t
    DirectFdStream::read(char * data, uint64_t nbytes)
    {
      return ::read(fd_, data, nbytes);
    }

    int64_t
    DirectFdStream::readv(const struct iovec *iov, int iovcnt)
    {
      return ::readv(fd_, iov, iovcnt < IOV_MAX ? iovcnt : IOV_MAX);
    }

    void
    DirectFdStream::close()
    {
      assert(own_fd_);
      if (own_fd_ && fd_ >= 0)
      {
        int fd = fd_;
        fd_    = -1;
        ::close(fd);
      }
    }

    bool
    DirectFdStream::stat() const
    {
      struct ::stat st;
      if (::fstat(fd_, &st))
        return false;
      mode_ = st.st_mode;
      return true;
    }

#ifdef __linux__
    static int64_t copySendfile(DirectFdStream & input,
                                DirectFdStream & output,
                                int64_t          max_bytes)
    {
      int64_t total = 0;

      while (total < max_bytes || max_bytes == 0) {
        int64_t limit;

        if (max_bytes == 0)
          limit = std::numeric_limits<int64_t>::max();
        else
          limit = max_bytes - total;

        ssize_t bytes = ::sendfile(output.fd(), input.fd(), nullptr, limit);
        if (bytes <= 0) {
          if (errno == EAGAIN)
            continue;
          return total;
        }
        total += bytes;
      }
      return total;
    }

    static int64_t copySplice(DirectFdStream & input,
                              DirectFdStream & output,
                              int64_t          max_bytes)
    {
      int64_t total = 0;

      while (total < max_bytes || max_bytes == 0) {
        int64_t limit;

        if (max_bytes == 0)
          limit = std::numeric_limits<int64_t>::max();
        else
          limit = max_bytes - total;

        ssize_t bytes = ::splice(input.fd(), nullptr, output.fd(), nullptr, limit, 0);
        if (bytes <= 0) {
          if (errno == EAGAIN)
            continue;
          return total;
        }
        total += bytes;
      }
      return total;
    }

    static int64_t copySpliceAny(DirectFdStream & input,
                                 DirectFdStream & output,
                                 int64_t          max_bytes)
    {
      int     pfd[2];
      int64_t total = 0;

      if (::pipe2(pfd, O_CLOEXEC | O_NONBLOCK))
        return -1;

      while (total < max_bytes || max_bytes == 0) {
        int64_t limit;

        if (max_bytes == 0)
          limit = std::numeric_limits<int64_t>::max();
        else
          limit = max_bytes - total;

        ssize_t rbytes = ::splice(input.fd(), nullptr, pfd[1], nullptr, limit, 0);
        if (bytes <= 0) {
          if (errno == EAGAIN)
            continue;
          goto end;
        }

        while (rbytes > 0) {
          ssize_t wbytes = ::splice(pfd[0], nullptr, output.fd(), nullptr, rbytes, 0);
          if (wbytes < 0) {
            if (errno == EAGAIN)
              continue;
            total = -1;
            goto end;
          }

          total  += wbytes;
          rbytes -= wbytes;
        }
      }

      end:
      ::close(pfd[0]);
      ::close(pfd[1]);
      return total;
    }
#endif // __linux__

    int64_t copy(DirectFdStream & input,
                 DirectFdStream & output,
                 int64_t          max_bytes)
    {

#ifdef __linux__
      // disk to fd
      if (S_ISREG(input.fdMode()))
        return copySendfile(input, output, max_bytes);

      // from a pipe or to a pipe
      if (S_ISFIFO(input.fdMode()) || S_ISFIFO(output.fdMode()))
        return copySplice(input, output, max_bytes);

      // splice: input -> pipe -> output
      if (max_bytes == 0 || max_bytes > 4096)
        return copySpliceAny(input, output, max_bytes);
#endif // __linux__

      // user copy
      return copy(static_cast<Stream &> (input),
                  static_cast<Stream &> (output),
                  max_bytes);
    }
  }
}
<|endoftext|>


<commit_before>#ifdef CAN_EMULATOR

#include "usbutil.h"
#include "canread.h"
#include "serialutil.h"
#include "ethernetutil.h"
#include "log.h"
#include <stdlib.h>

#define NUMERICAL_SIGNAL_COUNT 11
#define BOOLEAN_SIGNAL_COUNT 5
#define STATE_SIGNAL_COUNT 2
#define EVENT_SIGNAL_COUNT 1

extern Listener listener;

const char* NUMERICAL_SIGNALS[NUMERICAL_SIGNAL_COUNT] = {
    "steering_wheel_angle",
    "torque_at_transmission",
    "engine_speed",
    "vehicle_speed",
    "accelerator_pedal_position",
    "odometer",
    "fine_odometer_since_restart",
    "latitude",
    "longitude",
    "fuel_level",
    "fuel_consumed_since_restart",
};

const char* BOOLEAN_SIGNALS[BOOLEAN_SIGNAL_COUNT] = {
    "parking_brake_status",
    "brake_pedal_status",
    "headlamp_status",
    "high_beam_status",
    "windshield_wiper_status",
};

const char* STATE_SIGNALS[STATE_SIGNAL_COUNT] = {
    "transmission_gear_position",
    "ignition_status",
};

const char* SIGNAL_STATES[STATE_SIGNAL_COUNT][3] = {
    { "neutral", "first", "second" },
    { "off", "run", "accessory" },
};

const char* EVENT_SIGNALS[EVENT_SIGNAL_COUNT] = {
    "door_status",
};

struct Event {
    const char* value;
    bool event;
};

Event EVENT_SIGNAL_STATES[EVENT_SIGNAL_COUNT][3] = {
    { {"driver", false}, {"passenger", true}, {"rear_right", true}},
};

void setup() {
    srand(42);
}

bool usbWriteStub(uint8_t* buffer) {
    debug("Ignoring write request -- running an emulator\r\n");
    return true;
}

void loop() {
    sendNumericalMessage(
            NUMERICAL_SIGNALS[rand() % NUMERICAL_SIGNAL_COUNT],
            rand() % 50 + rand() % 100 * .1, &listener);
    sendBooleanMessage(BOOLEAN_SIGNALS[rand() % BOOLEAN_SIGNAL_COUNT],
            rand() % 2 == 1 ? true : false, &listener);

    int stateSignalIndex = rand() % STATE_SIGNAL_COUNT;
    sendStringMessage(STATE_SIGNALS[stateSignalIndex],
            SIGNAL_STATES[stateSignalIndex][rand() % 3], &listener);

    int eventSignalIndex = rand() % EVENT_SIGNAL_COUNT;
    Event randomEvent = EVENT_SIGNAL_STATES[eventSignalIndex][rand() % 3];
    sendEventedBooleanMessage(EVENT_SIGNALS[eventSignalIndex],
            randomEvent.value, randomEvent.event, &listener);

    readFromHost(listener.usb, usbWriteStub);
    readFromSerial(listener.serial, usbWriteStub);
}

void reset() { }

const char* getMessageSet() {
    return "emulator";
}

#endif // CAN_EMULATOR
<commit_msg>Slow down emulator speed by sending every nth time through the loop.<commit_after>#ifdef CAN_EMULATOR

#include "usbutil.h"
#include "canread.h"
#include "serialutil.h"
#include "ethernetutil.h"
#include "log.h"
#include <stdlib.h>

#define NUMERICAL_SIGNAL_COUNT 11
#define BOOLEAN_SIGNAL_COUNT 5
#define STATE_SIGNAL_COUNT 2
#define EVENT_SIGNAL_COUNT 1
#define EMULATOR_SEND_FREQUENCY 4

int emulatorRateLimiter = 0;

extern Listener listener;

const char* NUMERICAL_SIGNALS[NUMERICAL_SIGNAL_COUNT] = {
    "steering_wheel_angle",
    "torque_at_transmission",
    "engine_speed",
    "vehicle_speed",
    "accelerator_pedal_position",
    "odometer",
    "fine_odometer_since_restart",
    "latitude",
    "longitude",
    "fuel_level",
    "fuel_consumed_since_restart",
};

const char* BOOLEAN_SIGNALS[BOOLEAN_SIGNAL_COUNT] = {
    "parking_brake_status",
    "brake_pedal_status",
    "headlamp_status",
    "high_beam_status",
    "windshield_wiper_status",
};

const char* STATE_SIGNALS[STATE_SIGNAL_COUNT] = {
    "transmission_gear_position",
    "ignition_status",
};

const char* SIGNAL_STATES[STATE_SIGNAL_COUNT][3] = {
    { "neutral", "first", "second" },
    { "off", "run", "accessory" },
};

const char* EVENT_SIGNALS[EVENT_SIGNAL_COUNT] = {
    "door_status",
};

struct Event {
    const char* value;
    bool event;
};

Event EVENT_SIGNAL_STATES[EVENT_SIGNAL_COUNT][3] = {
    { {"driver", false}, {"passenger", true}, {"rear_right", true}},
};

void setup() {
    srand(42);
}

bool usbWriteStub(uint8_t* buffer) {
    debug("Ignoring write request -- running an emulator\r\n");
    return true;
}

void loop() {
    ++emulatorRateLimiter;
    if(emulatorRateLimiter >= EMULATOR_SEND_FREQUENCY) {
        emulatorRateLimiter = 0;

        sendNumericalMessage(
                NUMERICAL_SIGNALS[rand() % NUMERICAL_SIGNAL_COUNT],
                rand() % 50 + rand() % 100 * .1, &listener);
        sendBooleanMessage(BOOLEAN_SIGNALS[rand() % BOOLEAN_SIGNAL_COUNT],
                rand() % 2 == 1 ? true : false, &listener);

        int stateSignalIndex = rand() % STATE_SIGNAL_COUNT;
        sendStringMessage(STATE_SIGNALS[stateSignalIndex],
                SIGNAL_STATES[stateSignalIndex][rand() % 3], &listener);

        int eventSignalIndex = rand() % EVENT_SIGNAL_COUNT;
        Event randomEvent = EVENT_SIGNAL_STATES[eventSignalIndex][rand() % 3];
        sendEventedBooleanMessage(EVENT_SIGNALS[eventSignalIndex],
                randomEvent.value, randomEvent.event, &listener);
    }

    readFromHost(listener.usb, usbWriteStub);
    readFromSerial(listener.serial, usbWriteStub);
}

void reset() { }

const char* getMessageSet() {
    return "emulator";
}

#endif // CAN_EMULATOR
<|endoftext|>


<commit_before>#include "disassembler.h"
#include "util.h"

using namespace std;

struct program {
	char name[7];
	//TODO
	program() {
		for ( int i = 0 ; i < 7 ; i++ ) {
			name[i] = 0;
		}
		//TODO
	}
};

bool read_record(ifstream &ifile, string &record);
void record_to_memory(const string record, program &p);
void write_assembly(const program &p, ofstream &ofile);

bool disassemble(ifstream &ifile, ofstream &ofile) {
	string record;
	program p;
	while ( read_record(ifile, record) ) {
		record_to_memory(record, p);
	}
	status("Done reading records");
	write_assembly(p, ofile);
	status("Done writing output file");
}

bool read_record(ifstream &ifile, string &record) {
	char t;
	do {
		t = ifile.get();
		if ( t == EOF ) {
			return false;
		}
	} while ( t == '\n' || t == ' ' );
	record = "";
	record += t;
	switch (t) {
		case 'H': // Header
			for ( int col = 2 ; col <= 19 ; col++ ) {
				t = ifile.get();
				if ( t == EOF ) {
					fatal("Unexpected end of Header Record");
				}
				record += t;
			}
			break;
		case 'T': // Text
			//TODO
			break;
		case 'E': // End
			//TODO
			break;
		default:
			fatal("Unknown record type " + t);
	}
	return true;
}

void record_to_memory(const string record, program &p) {
	// TODO
}

void write_assembly(const program &p, ofstream &ofile) {
	// TODO
}<commit_msg>Add end record reader<commit_after>#include "disassembler.h"
#include "util.h"

using namespace std;

struct program {
	char name[7];
	//TODO
	program() {
		for ( int i = 0 ; i < 7 ; i++ ) {
			name[i] = 0;
		}
		//TODO
	}
};

bool read_record(ifstream &ifile, string &record);
void record_to_memory(const string record, program &p);
void write_assembly(const program &p, ofstream &ofile);

bool disassemble(ifstream &ifile, ofstream &ofile) {
	string record;
	program p;
	while ( read_record(ifile, record) ) {
		record_to_memory(record, p);
	}
	status("Done reading records");
	write_assembly(p, ofile);
	status("Done writing output file");
}

bool read_record(ifstream &ifile, string &record) {
	char t;
	do {
		t = ifile.get();
		if ( t == EOF ) {
			return false;
		}
	} while ( t == '\n' || t == ' ' );
	record = "";
	record += t;
	switch (t) {
		case 'H': // Header
			for ( int col = 2 ; col <= 19 ; col++ ) {
				t = ifile.get();
				if ( t == EOF ) {
					fatal("Unexpected end of Header Record");
				}
				record += t;
			}
			break;
		case 'T': // Text
			//TODO
			break;
		case 'E': // End
			for ( int col = 2 ; col <= 7 ; col++ ) {
				t = ifile.get();
				if ( t == EOF ) {
					fatal("Unexpected end of End Record");
				}
				record += t;
			}
			break;
		default:
			fatal("Unknown record type " + t);
	}
	return true;
}

void record_to_memory(const string record, program &p) {
	// TODO
}

void write_assembly(const program &p, ofstream &ofile) {
	// TODO
}<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016 Eugene Lazin <4lazin@gmail.com>, Mark Adler <madler@alumni.caltech.edu>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "util.h"
#include <stdio.h>
#include <cassert>
#include <chrono>
#include <thread>
#include <sstream>
#include <iostream>

#include <sys/mman.h>

#include "akumuli_def.h"
#include "log_iface.h"

namespace Akumuli
{

std::string apr_error_message(apr_status_t status) {
    char error_message[0x100];
    apr_strerror(status, error_message, 0x100);
    return std::string(error_message);
}

static void aku_empty_panic_handler(const char* msg) {
    // This is default panic handler, it does nothing.
    // After panic handler returns - akumuli will
    // throw exception.
}

static aku_panic_handler_t g_panic_handler = &aku_empty_panic_handler;

void set_panic_handler(aku_panic_handler_t new_panic_handler) {
    g_panic_handler = new_panic_handler;
}

// coverity[+kill]
AprException::AprException(apr_status_t status, const char* message)
    : std::runtime_error(message)
    , status(status)
{
    (*g_panic_handler)(message);
}

std::ostream& operator << (std::ostream& str, AprException const& e) {
    str << "Error: " << e.what() << ", status: " << e.status << ".";
    return str;
}

// coverity[+kill]
Exception::Exception(const char* message)
    : std::runtime_error(message)
{
    (*g_panic_handler)(message);
}

// coverity[+kill]
Exception::Exception(std::string message)
    : std::runtime_error(message)
{
    (*g_panic_handler)(message.c_str());
}

std::ostream& operator << (std::ostream& str, Exception const& e) {
    str << e.what();
    return str;
}

MemoryMappedFile::MemoryMappedFile(const char* file_name, bool enable_huge_tlb)
    : mem_pool_()
    , mmap_()
    , fp_()
    , finfo_()
    , status_(APR_EINIT)
    , path_(file_name)
    , enable_huge_tlb_(enable_huge_tlb)
{
    map_file();
}

void MemoryMappedFile::move_file(const char* new_name) {
    status_ = apr_file_rename(path_.c_str(), new_name, mem_pool_);
    if (status_ == APR_SUCCESS) {
        path_ = new_name;
    }
}

void MemoryMappedFile::delete_file() {
    using namespace std;
    status_ = apr_file_remove(path_.c_str(), mem_pool_);
    if (status_ != APR_SUCCESS) {
        stringstream fmt;
        fmt << "Can't remove file " << path_ << " error " << error_message();
        Logger::msg(AKU_LOG_ERROR, fmt.str().c_str());
    }
}

apr_status_t MemoryMappedFile::map_file() {
    using namespace std;
    int success_count = 0;
    status_ = apr_pool_create(&mem_pool_, NULL);
    if (status_ == APR_SUCCESS) {
        success_count++;
        status_ = apr_file_open(&fp_, path_.c_str(), APR_WRITE|APR_READ, APR_OS_DEFAULT, mem_pool_);
        if (status_ == APR_SUCCESS) {
            success_count++;
            status_ = apr_file_lock(fp_, APR_FLOCK_EXCLUSIVE);
            if (status_ == APR_SUCCESS) {
                // No need to increment success_count, no cleanup needed for apr_file_lock
                status_ = apr_file_info_get(&finfo_, APR_FINFO_SIZE, fp_);
                if (status_ == APR_SUCCESS) {
                    success_count++;
                    apr_int32_t flags = APR_MMAP_WRITE | APR_MMAP_READ;
                    if (enable_huge_tlb_) {
                        flags |= MAP_HUGETLB;
                    }
                    status_ = apr_mmap_create(&mmap_, fp_, 0, finfo_.size, flags, mem_pool_);
                    if (status_ == APR_SUCCESS)
                        success_count++; }}}}

    if (status_ != APR_SUCCESS) {
        free_resources(success_count);
        stringstream err;
        err << "Can't mmap file " << path_ << ", error " << error_message() << " on step " << success_count;
        Logger::msg(AKU_LOG_ERROR, err.str().c_str());
    }
    return status_;
}

void MemoryMappedFile::remap_file_destructive() {
    using namespace std;
    apr_off_t file_size = finfo_.size;
    free_resources(4);
    apr_pool_t* pool;
    apr_file_t* file_ptr;
    apr_status_t status;
    int success_counter = 0;
    status = apr_pool_create(&pool, NULL);
    if (status == APR_SUCCESS) {
        success_counter++;
        status = apr_file_open(&file_ptr, path_.c_str(), APR_WRITE, APR_OS_DEFAULT, pool);
        if (status == APR_SUCCESS) {
            success_counter++;
            status = apr_file_trunc(file_ptr, 0);
            if (status == APR_SUCCESS) {
                success_counter++;
                status = apr_file_trunc(file_ptr, file_size);
                if (status == APR_SUCCESS) {
                    success_counter++;
                }
            }
        }
    }
    switch(success_counter) {
        case 4:
        case 3:
        case 2:
            apr_file_close(file_ptr);
        case 1:
            apr_pool_destroy(pool);
    };
    if (status != APR_SUCCESS) {
        stringstream err;
        err << "Can't remap file " << path_ << " error " << apr_error_message(status) << " on step " << success_counter;
        Logger::msg(AKU_LOG_ERROR, err.str().c_str());
        AKU_PANIC("can't remap file");
    }
    status = map_file();
    if (status != APR_SUCCESS) {
        stringstream err;
        err << "Can't remap file " << path_ << " error " << apr_error_message(status) << " on step " << success_counter;
        Logger::msg(AKU_LOG_ERROR, err.str().c_str());
        AKU_PANIC("can't remap file");
    }
}

bool MemoryMappedFile::is_bad() const {
    return status_ != APR_SUCCESS;
}

std::string MemoryMappedFile::error_message() const {
    char error_message[0x100];
    apr_strerror(status_, error_message, 0x100);
    return std::string(error_message);
}

apr_status_t MemoryMappedFile::status_code() const {
    return status_;
}

void MemoryMappedFile::panic_if_bad() {
    if (status_ != APR_SUCCESS) {
        char error_message[0x100];
        apr_strerror(status_, error_message, 0x100);
        AKU_APR_PANIC(status_, error_message);
    }
}

/* Why not std::unique_ptr with custom deleter?
 * To make finalization order explicit and prevent null-reference errors in
 * APR finalizers. Resource finalizers in APR can't handle null pointers,
 * so we will need to wrap each `close` or `destroy` or whatsever
 * function to be able to pass it to unique_ptr c-tor as deleter.
 */

void MemoryMappedFile::free_resources(int cnt)
{
    switch(cnt)
    {
    default:
    case 4:
        apr_mmap_delete(mmap_);
    case 3:
    case 2:
        apr_file_close(fp_);
    case 1:
        apr_pool_destroy(mem_pool_);
    };
}

MemoryMappedFile::~MemoryMappedFile() {
    if (!is_bad())
        free_resources(4);
}

void* MemoryMappedFile::get_pointer() const {
    return mmap_->mm;
}

size_t MemoryMappedFile::get_size() const {
    return mmap_->size;
}

apr_status_t MemoryMappedFile::flush() {
    return flush(0, mmap_->size);
}

aku_Status MemoryMappedFile::protect_all() {
    if (!mprotect(mmap_->mm, mmap_->size, PROT_READ)) {
        return AKU_SUCCESS;
    }
    int err = errno;
    aku_Status ret = AKU_EGENERAL;
    switch(err) {
    case ENOMEM:
        ret = AKU_ENO_MEM;
        break;
    case EACCES:
        ret = AKU_EBAD_DATA;
        break;
    };
    return ret;
}

aku_Status MemoryMappedFile::unprotect_all() {
    if (!mprotect(mmap_->mm, mmap_->size, PROT_WRITE)) {
        return AKU_SUCCESS;
    }
    int err = errno;
    aku_Status ret = AKU_EGENERAL;
    switch(err) {
    case ENOMEM:
        ret = AKU_ENO_MEM;
        break;
    case EACCES:
        ret = AKU_EBAD_DATA;
        break;
    };
    return ret;
}

apr_status_t MemoryMappedFile::flush(size_t from, size_t to) {
    void* p = align_to_page(static_cast<char*>(mmap_->mm) + from, get_page_size());
    size_t len = to - from;
    if (msync(p, len, MS_SYNC) == 0) {
        return AKU_SUCCESS;
    }
    int e = errno;
    switch(e) {
    case EBUSY:
        Logger::msg(AKU_LOG_ERROR, "Can't msync, busy");
        return AKU_EBUSY;
    case EINVAL:
    case ENOMEM:
        Logger::msg(AKU_LOG_ERROR, "Invalid args passed to msync");
        return AKU_EBAD_ARG;
    default:
        Logger::msg(AKU_LOG_ERROR, "Unknown msync error");
    };
    return AKU_EGENERAL;
}

i64 log2(i64 value) {
    return static_cast<i64>(8*sizeof(u64) - __builtin_clzll((u64)value) - 1);
}

const void* align_to_page(const void* ptr, size_t page_size) {
    return reinterpret_cast<const void*>(
        reinterpret_cast<unsigned long long>(ptr) & ~(page_size - 1));
}

void* align_to_page(void* ptr, size_t page_size) {
    return reinterpret_cast<void*>(
        reinterpret_cast<unsigned long long>(ptr) & ~(page_size - 1));
}

void prefetch_mem(const void* ptr, size_t mem_size) {
    auto aptr = align_to_page(ptr, get_page_size());
    int err = madvise(const_cast<void*>(aptr), mem_size, MADV_WILLNEED);
    switch(err) {
    case EBADF:
        AKU_PANIC("(madvise) the map exists, but the area maps something that isn't a file");
    case EINVAL:
        // Severe error - panic!
        AKU_PANIC("(madvise) the value is negative | addr is not page-aligned | advice is not a valid value |...");
    case EAGAIN: //  A kernel resource was temporarily unavailable.
    case EIO:    // Paging  in  this  area  would  exceed  the process's maximum resident set size.
    case ENOMEM: // Not enough memory: paging in failed.
    default:
        break;
    };
    auto begin = static_cast<const char*>(aptr);
    auto end = begin + mem_size;
    auto step = get_page_size();
    volatile char acc = 0;
    while(begin < end) {
        acc += *begin;
        begin += step;
    }
}

size_t get_page_size() {
    auto page_size = sysconf(_SC_PAGESIZE);
    if (AKU_UNLIKELY(page_size < 0)) {
        AKU_PANIC("sysconf error, can't get _SC_PAGESIZE");
    }
    return static_cast<size_t>(page_size);
}

Rand::Rand()
    : rand_()
{
    typename std::chrono::system_clock seed_clock;
    auto init_seed = static_cast<unsigned>(seed_clock.now().time_since_epoch().count());
    rand_.seed(init_seed);
}

u32 Rand::operator () () {
    return (u32)rand_();
}

RWLock::RWLock()
    : rwlock_ PTHREAD_RWLOCK_INITIALIZER
{
    int error = pthread_rwlock_init(&rwlock_, nullptr);
    if (error) {
        AKU_PANIC("pthread_rwlock_init error");
    }
}

RWLock::~RWLock() {
    pthread_rwlock_destroy(&rwlock_);
}

void RWLock::rdlock() {
    int err = pthread_rwlock_rdlock(&rwlock_);
    if (err) {
        AKU_PANIC("pthread_rwlock_rdlock error");
    }
}

bool RWLock::try_rdlock() {
    int err = pthread_rwlock_tryrdlock(&rwlock_);
    switch(err) {
    case 0:
        return true;
    case EBUSY:
    case EDEADLK:
        return false;
    default:
        break;
    }
    AKU_PANIC("pthread_rwlock_tryrdlock error");
}

void RWLock::wrlock() {
    int err = pthread_rwlock_wrlock(&rwlock_);
    if (err) {
        AKU_PANIC("pthread_rwlock_wrlock error");
    }
}

bool RWLock::try_wrlock() {
    int err = pthread_rwlock_trywrlock(&rwlock_);
    switch(err) {
    case 0:
        return true;
    case EBUSY:
    case EDEADLK:
        return false;
    default:
        break;
    }
    AKU_PANIC("pthread_rwlock_trywrlock error");
}

void RWLock::unlock() {
    int err = pthread_rwlock_unlock(&rwlock_);
    if (err) {
        AKU_PANIC("pthread_rwlock_unlock error");
    }
}

bool same_value(double a, double b) {
    union Bits {
        double d;
        u64 u;
    };
    Bits ba = {};
    ba.d = a;
    Bits bb = {};
    bb.d = b;
    return ba.u == bb.u;
}

}

<commit_msg>There's no MAP_HUGETLB os OS X.<commit_after>/**
 * Copyright (c) 2016 Eugene Lazin <4lazin@gmail.com>, Mark Adler <madler@alumni.caltech.edu>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "util.h"
#include <stdio.h>
#include <cassert>
#include <chrono>
#include <thread>
#include <sstream>
#include <iostream>

#include <sys/mman.h>

#include "akumuli_def.h"
#include "log_iface.h"

namespace Akumuli
{

std::string apr_error_message(apr_status_t status) {
    char error_message[0x100];
    apr_strerror(status, error_message, 0x100);
    return std::string(error_message);
}

static void aku_empty_panic_handler(const char* msg) {
    // This is default panic handler, it does nothing.
    // After panic handler returns - akumuli will
    // throw exception.
}

static aku_panic_handler_t g_panic_handler = &aku_empty_panic_handler;

void set_panic_handler(aku_panic_handler_t new_panic_handler) {
    g_panic_handler = new_panic_handler;
}

// coverity[+kill]
AprException::AprException(apr_status_t status, const char* message)
    : std::runtime_error(message)
    , status(status)
{
    (*g_panic_handler)(message);
}

std::ostream& operator << (std::ostream& str, AprException const& e) {
    str << "Error: " << e.what() << ", status: " << e.status << ".";
    return str;
}

// coverity[+kill]
Exception::Exception(const char* message)
    : std::runtime_error(message)
{
    (*g_panic_handler)(message);
}

// coverity[+kill]
Exception::Exception(std::string message)
    : std::runtime_error(message)
{
    (*g_panic_handler)(message.c_str());
}

std::ostream& operator << (std::ostream& str, Exception const& e) {
    str << e.what();
    return str;
}

MemoryMappedFile::MemoryMappedFile(const char* file_name, bool enable_huge_tlb)
    : mem_pool_()
    , mmap_()
    , fp_()
    , finfo_()
    , status_(APR_EINIT)
    , path_(file_name)
    , enable_huge_tlb_(enable_huge_tlb)
{
    map_file();
}

void MemoryMappedFile::move_file(const char* new_name) {
    status_ = apr_file_rename(path_.c_str(), new_name, mem_pool_);
    if (status_ == APR_SUCCESS) {
        path_ = new_name;
    }
}

void MemoryMappedFile::delete_file() {
    using namespace std;
    status_ = apr_file_remove(path_.c_str(), mem_pool_);
    if (status_ != APR_SUCCESS) {
        stringstream fmt;
        fmt << "Can't remove file " << path_ << " error " << error_message();
        Logger::msg(AKU_LOG_ERROR, fmt.str().c_str());
    }
}

apr_status_t MemoryMappedFile::map_file() {
    using namespace std;
    int success_count = 0;
    status_ = apr_pool_create(&mem_pool_, NULL);
    if (status_ == APR_SUCCESS) {
        success_count++;
        status_ = apr_file_open(&fp_, path_.c_str(), APR_WRITE|APR_READ, APR_OS_DEFAULT, mem_pool_);
        if (status_ == APR_SUCCESS) {
            success_count++;
            status_ = apr_file_lock(fp_, APR_FLOCK_EXCLUSIVE);
            if (status_ == APR_SUCCESS) {
                // No need to increment success_count, no cleanup needed for apr_file_lock
                status_ = apr_file_info_get(&finfo_, APR_FINFO_SIZE, fp_);
                if (status_ == APR_SUCCESS) {
                    success_count++;
                    apr_int32_t flags = APR_MMAP_WRITE | APR_MMAP_READ;
                    if (enable_huge_tlb_) {
#if defined MAP_HUGETLB
						flags |= MAP_HUGETLB;
#endif
                    }
                    status_ = apr_mmap_create(&mmap_, fp_, 0, finfo_.size, flags, mem_pool_);
                    if (status_ == APR_SUCCESS)
                        success_count++; }}}}

    if (status_ != APR_SUCCESS) {
        free_resources(success_count);
        stringstream err;
        err << "Can't mmap file " << path_ << ", error " << error_message() << " on step " << success_count;
        Logger::msg(AKU_LOG_ERROR, err.str().c_str());
    }
    return status_;
}

void MemoryMappedFile::remap_file_destructive() {
    using namespace std;
    apr_off_t file_size = finfo_.size;
    free_resources(4);
    apr_pool_t* pool;
    apr_file_t* file_ptr;
    apr_status_t status;
    int success_counter = 0;
    status = apr_pool_create(&pool, NULL);
    if (status == APR_SUCCESS) {
        success_counter++;
        status = apr_file_open(&file_ptr, path_.c_str(), APR_WRITE, APR_OS_DEFAULT, pool);
        if (status == APR_SUCCESS) {
            success_counter++;
            status = apr_file_trunc(file_ptr, 0);
            if (status == APR_SUCCESS) {
                success_counter++;
                status = apr_file_trunc(file_ptr, file_size);
                if (status == APR_SUCCESS) {
                    success_counter++;
                }
            }
        }
    }
    switch(success_counter) {
        case 4:
        case 3:
        case 2:
            apr_file_close(file_ptr);
        case 1:
            apr_pool_destroy(pool);
    };
    if (status != APR_SUCCESS) {
        stringstream err;
        err << "Can't remap file " << path_ << " error " << apr_error_message(status) << " on step " << success_counter;
        Logger::msg(AKU_LOG_ERROR, err.str().c_str());
        AKU_PANIC("can't remap file");
    }
    status = map_file();
    if (status != APR_SUCCESS) {
        stringstream err;
        err << "Can't remap file " << path_ << " error " << apr_error_message(status) << " on step " << success_counter;
        Logger::msg(AKU_LOG_ERROR, err.str().c_str());
        AKU_PANIC("can't remap file");
    }
}

bool MemoryMappedFile::is_bad() const {
    return status_ != APR_SUCCESS;
}

std::string MemoryMappedFile::error_message() const {
    char error_message[0x100];
    apr_strerror(status_, error_message, 0x100);
    return std::string(error_message);
}

apr_status_t MemoryMappedFile::status_code() const {
    return status_;
}

void MemoryMappedFile::panic_if_bad() {
    if (status_ != APR_SUCCESS) {
        char error_message[0x100];
        apr_strerror(status_, error_message, 0x100);
        AKU_APR_PANIC(status_, error_message);
    }
}

/* Why not std::unique_ptr with custom deleter?
 * To make finalization order explicit and prevent null-reference errors in
 * APR finalizers. Resource finalizers in APR can't handle null pointers,
 * so we will need to wrap each `close` or `destroy` or whatsever
 * function to be able to pass it to unique_ptr c-tor as deleter.
 */

void MemoryMappedFile::free_resources(int cnt)
{
    switch(cnt)
    {
    default:
    case 4:
        apr_mmap_delete(mmap_);
    case 3:
    case 2:
        apr_file_close(fp_);
    case 1:
        apr_pool_destroy(mem_pool_);
    };
}

MemoryMappedFile::~MemoryMappedFile() {
    if (!is_bad())
        free_resources(4);
}

void* MemoryMappedFile::get_pointer() const {
    return mmap_->mm;
}

size_t MemoryMappedFile::get_size() const {
    return mmap_->size;
}

apr_status_t MemoryMappedFile::flush() {
    return flush(0, mmap_->size);
}

aku_Status MemoryMappedFile::protect_all() {
    if (!mprotect(mmap_->mm, mmap_->size, PROT_READ)) {
        return AKU_SUCCESS;
    }
    int err = errno;
    aku_Status ret = AKU_EGENERAL;
    switch(err) {
    case ENOMEM:
        ret = AKU_ENO_MEM;
        break;
    case EACCES:
        ret = AKU_EBAD_DATA;
        break;
    };
    return ret;
}

aku_Status MemoryMappedFile::unprotect_all() {
    if (!mprotect(mmap_->mm, mmap_->size, PROT_WRITE)) {
        return AKU_SUCCESS;
    }
    int err = errno;
    aku_Status ret = AKU_EGENERAL;
    switch(err) {
    case ENOMEM:
        ret = AKU_ENO_MEM;
        break;
    case EACCES:
        ret = AKU_EBAD_DATA;
        break;
    };
    return ret;
}

apr_status_t MemoryMappedFile::flush(size_t from, size_t to) {
    void* p = align_to_page(static_cast<char*>(mmap_->mm) + from, get_page_size());
    size_t len = to - from;
    if (msync(p, len, MS_SYNC) == 0) {
        return AKU_SUCCESS;
    }
    int e = errno;
    switch(e) {
    case EBUSY:
        Logger::msg(AKU_LOG_ERROR, "Can't msync, busy");
        return AKU_EBUSY;
    case EINVAL:
    case ENOMEM:
        Logger::msg(AKU_LOG_ERROR, "Invalid args passed to msync");
        return AKU_EBAD_ARG;
    default:
        Logger::msg(AKU_LOG_ERROR, "Unknown msync error");
    };
    return AKU_EGENERAL;
}

i64 log2(i64 value) {
    return static_cast<i64>(8*sizeof(u64) - __builtin_clzll((u64)value) - 1);
}

const void* align_to_page(const void* ptr, size_t page_size) {
    return reinterpret_cast<const void*>(
        reinterpret_cast<unsigned long long>(ptr) & ~(page_size - 1));
}

void* align_to_page(void* ptr, size_t page_size) {
    return reinterpret_cast<void*>(
        reinterpret_cast<unsigned long long>(ptr) & ~(page_size - 1));
}

void prefetch_mem(const void* ptr, size_t mem_size) {
    auto aptr = align_to_page(ptr, get_page_size());
    int err = madvise(const_cast<void*>(aptr), mem_size, MADV_WILLNEED);
    switch(err) {
    case EBADF:
        AKU_PANIC("(madvise) the map exists, but the area maps something that isn't a file");
    case EINVAL:
        // Severe error - panic!
        AKU_PANIC("(madvise) the value is negative | addr is not page-aligned | advice is not a valid value |...");
    case EAGAIN: //  A kernel resource was temporarily unavailable.
    case EIO:    // Paging  in  this  area  would  exceed  the process's maximum resident set size.
    case ENOMEM: // Not enough memory: paging in failed.
    default:
        break;
    };
    auto begin = static_cast<const char*>(aptr);
    auto end = begin + mem_size;
    auto step = get_page_size();
    volatile char acc = 0;
    while(begin < end) {
        acc += *begin;
        begin += step;
    }
}

size_t get_page_size() {
    auto page_size = sysconf(_SC_PAGESIZE);
    if (AKU_UNLIKELY(page_size < 0)) {
        AKU_PANIC("sysconf error, can't get _SC_PAGESIZE");
    }
    return static_cast<size_t>(page_size);
}

Rand::Rand()
    : rand_()
{
    typename std::chrono::system_clock seed_clock;
    auto init_seed = static_cast<unsigned>(seed_clock.now().time_since_epoch().count());
    rand_.seed(init_seed);
}

u32 Rand::operator () () {
    return (u32)rand_();
}

RWLock::RWLock()
    : rwlock_ PTHREAD_RWLOCK_INITIALIZER
{
    int error = pthread_rwlock_init(&rwlock_, nullptr);
    if (error) {
        AKU_PANIC("pthread_rwlock_init error");
    }
}

RWLock::~RWLock() {
    pthread_rwlock_destroy(&rwlock_);
}

void RWLock::rdlock() {
    int err = pthread_rwlock_rdlock(&rwlock_);
    if (err) {
        AKU_PANIC("pthread_rwlock_rdlock error");
    }
}

bool RWLock::try_rdlock() {
    int err = pthread_rwlock_tryrdlock(&rwlock_);
    switch(err) {
    case 0:
        return true;
    case EBUSY:
    case EDEADLK:
        return false;
    default:
        break;
    }
    AKU_PANIC("pthread_rwlock_tryrdlock error");
}

void RWLock::wrlock() {
    int err = pthread_rwlock_wrlock(&rwlock_);
    if (err) {
        AKU_PANIC("pthread_rwlock_wrlock error");
    }
}

bool RWLock::try_wrlock() {
    int err = pthread_rwlock_trywrlock(&rwlock_);
    switch(err) {
    case 0:
        return true;
    case EBUSY:
    case EDEADLK:
        return false;
    default:
        break;
    }
    AKU_PANIC("pthread_rwlock_trywrlock error");
}

void RWLock::unlock() {
    int err = pthread_rwlock_unlock(&rwlock_);
    if (err) {
        AKU_PANIC("pthread_rwlock_unlock error");
    }
}

bool same_value(double a, double b) {
    union Bits {
        double d;
        u64 u;
    };
    Bits ba = {};
    ba.d = a;
    Bits bb = {};
    bb.d = b;
    return ba.u == bb.u;
}

}

<|endoftext|>