<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_recovery_ffdc_cppm.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef __PM_RECOVERY_FFDC_CPPM_
#define __PM_RECOVERY_FFDC_CPPM_

///
/// @file   p9_pm_recovery_ffdc_cppm.H
/// @brief  CPPM FFDC collection of PM complex
///
/// *HWP HWP Owner:      Greg Still <stillgs@us.ibm.com>
/// *HWP FW Owner:       Prasad Bg Ranganath <prasadbgr@in.ibm.com>
/// *HWP Team:           PM
/// *HWP Level:          2
/// *HWP Consumed by:    Hostboot
//
// *INDENT-OFF*
//--------------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------------
#include <fapi2.H>
#include <stdint.h>
#include <p9_pm_recovery_ffdc_base.H>

namespace p9_stop_recov_ffdc
{

    class CppmRegs : public PlatPmComplex
    {
            public:
            /// @brief  constructor
            CppmRegs(const fapi2::Target< fapi2::TARGET_TYPE_PROC_CHIP > i_procChipTgt );

            /// @brief  destructor
            virtual ~CppmRegs () { };

            /// @brief      Initializes the Quad and CPPM FFDC Sub-Sections in HOMER with default headers
            /// @param[in]  i_pHomerBuf  points to base of P9 HOMER.
            ///  @return    fapi2 return code
            fapi2::ReturnCode init ( void* i_pHomerBuf );

            /// @brief      collects FFDC pertaining to all functional cores in the chip.
            /// @param[in]  i_pHomerBuf     points to base of P9 HOMER.
            /// @param[in]  i_ffdcType      indicates the content type to collect
            //  @return     fapi2 return code.
            fapi2::ReturnCode collectFfdc ( void*    i_pHomerBuf,
                                            uint8_t  i_ffdcType = ALL );

        private:
            /// @brief updates the CPPM FFDC Header
            ///@param[in]   i_pHomerBuf     points to a location in HOMER meant for CPPM Header
            ///@param[in]   i_CppmInstance  CPPM instance
            ///@param[in]   i_ffdcValid     non-zero indicates the CPPM FFDC is valid
            ///@return      fapi2 return code.

            fapi2::ReturnCode updateCppmFfdcHeader( uint8_t * i_pHomerBuf,
                                                    const uint8_t i_cppmInstance,
                                                    const uint16_t i_ffdcValid);
            /// @brief updates the QUAD FFDC Header
            ///@param[in]   i_pHomerBuf     points to a location in HOMER meant for Quad Header
            ///@param[in]   i_quadInstance  Quad instance
            ///@param[in]   i_ffdcValid     non-zero indicates the Quad FFDC is valid
            ///@return      fapi2 return code.

            fapi2::ReturnCode updateQuadFfdcHeader( uint8_t * i_pHomerBuf,
                                                    const uint8_t i_quadInstance,
                                                    const uint16_t i_ffdcValid);
    };

extern "C"
{
    typedef fapi2::ReturnCode( *p9_pm_recovery_ffdc_cppm_FP_t )
            ( const fapi2::Target< fapi2::TARGET_TYPE_PROC_CHIP > & i_procChipTgt,
              void * i_cppmFfdcBuf );
}

} //namespace p9_stop_recov_ffdc ends

#endif //PM_RECOVERY_FFDC_CPPM
<commit_msg>PM: Generation of summarized version of STOP Recovery FFDC.<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_recovery_ffdc_cppm.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef __PM_RECOVERY_FFDC_CPPM_
#define __PM_RECOVERY_FFDC_CPPM_

///
/// @file   p9_pm_recovery_ffdc_cppm.H
/// @brief  CPPM FFDC collection of PM complex
///
/// *HWP HWP Owner:      Greg Still <stillgs@us.ibm.com>
/// *HWP FW Owner:       Prasad Bg Ranganath <prasadbgr@in.ibm.com>
/// *HWP Team:           PM
/// *HWP Level:          2
/// *HWP Consumed by:    Hostboot
//
// *INDENT-OFF*
//--------------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------------
#include <fapi2.H>
#include <stdint.h>
#include <p9_pm_recovery_ffdc_base.H>

namespace p9_stop_recov_ffdc
{

    class CppmRegs : public PlatPmComplex
    {
            public:
            /// @brief  constructor
            CppmRegs(const fapi2::Target< fapi2::TARGET_TYPE_PROC_CHIP > i_procChipTgt );

            /// @brief  destructor
            virtual ~CppmRegs () { };

            /// @brief      Initializes the Quad and CPPM FFDC Sub-Sections in HOMER with default headers
            /// @param[in]  i_pHomerBuf  points to base of P9 HOMER.
            ///  @return    fapi2 return code
            fapi2::ReturnCode init ( void* i_pHomerBuf );

            /// @brief      collects FFDC pertaining to all functional cores in the chip.
            /// @param[in]  i_pHomerBuf     points to base of P9 HOMER.
            /// @param[in]  i_ffdcType      indicates the content type to collect
            //  @return     fapi2 return code.
            fapi2::ReturnCode collectFfdc ( void*    i_pHomerBuf,
                                            uint8_t  i_ffdcType = ALL );

            /// @brief      generates summary of FFDC pertaining to a given platform.
            /// @param[in]  i_pHomer    points to Homer base.
            /// @return     fapi2 return code
            fapi2::ReturnCode generateSummary( void * i_pHomer );
        private:

            ///@brief initializes a list of register for generation of FFDC summary.
            void initRegList();

            /// @brief updates the CPPM FFDC Header
            ///@param[in]   i_pHomerBuf     points to a location in HOMER meant for CPPM Header
            ///@param[in]   i_CppmInstance  CPPM instance
            ///@param[in]   i_ffdcValid     non-zero indicates the CPPM FFDC is valid
            ///@return      fapi2 return code.

            fapi2::ReturnCode updateCppmFfdcHeader( uint8_t * i_pHomerBuf,
                                                    const uint8_t i_cppmInstance,
                                                    const uint16_t i_ffdcValid);
            /// @brief updates the QUAD FFDC Header
            ///@param[in]   i_pHomerBuf     points to a location in HOMER meant for Quad Header
            ///@param[in]   i_quadInstance  Quad instance
            ///@param[in]   i_ffdcValid     non-zero indicates the Quad FFDC is valid
            ///@return      fapi2 return code.

            fapi2::ReturnCode updateQuadFfdcHeader( uint8_t * i_pHomerBuf,
                                                    const uint8_t i_quadInstance,
                                                    const uint16_t i_ffdcValid);
        private:
            std::vector<uint32_t> iv_cppmSummaryReg;
    };

    //---------------------------------------------------------------------------------------------
    // function pointer typedef definition for HWP call support
    typedef fapi2::ReturnCode( *p9_pm_recovery_ffdc_cppm_FP_t )
            ( const fapi2::Target< fapi2::TARGET_TYPE_PROC_CHIP > & i_procChipTgt,
              void * i_cppmFfdcBuf );
extern "C"
{
    // -----------------------------------------------------------------------------
    // Function prototypes
    // -----------------------------------------------------------------------------
    ///
    /// @brief Populates the PM FFDC section with FFDC collected from CPPM
    ///
    /// @param[in] i_procChipTarget Proc Chip target
    /// @param[in] i_pHomerImage    Pointer to the base of the chip HOMER region
    ///
    /// @return FAPI2_RC_SUCCESS on success or error return code
    ///
        fapi2::ReturnCode p9_pm_recovery_ffdc_cppm
        ( const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_procChipTarget,
          void* i_pHomerImage );
}

} //namespace p9_stop_recov_ffdc ends

#endif //PM_RECOVERY_FFDC_CPPM
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Endless Mobile
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * Written by:
 *     Jasper St. Pierre <jstpierre@mecheye.net>
 */

#include "value.h"
#include "gobject.h"

namespace GNodeJS {

v8::Handle<v8::Value> GIArgumentToV8(GITypeInfo *type_info, GIArgument *arg) {
    GITypeTag type_tag = g_type_info_get_tag (type_info);

    switch (type_tag) {
    case GI_TYPE_TAG_VOID:
        return v8::Undefined ();

    case GI_TYPE_TAG_BOOLEAN:
        if (arg->v_boolean)
            return v8::True ();
        else
            return v8::False ();

    case GI_TYPE_TAG_INT32:
        return v8::Integer::New (arg->v_int);
    case GI_TYPE_TAG_UINT32:
        return v8::Integer::NewFromUnsigned (arg->v_uint);
    case GI_TYPE_TAG_INT16:
        return v8::Integer::New (arg->v_int16);
    case GI_TYPE_TAG_UINT16:
        return v8::Integer::NewFromUnsigned (arg->v_uint16);
    case GI_TYPE_TAG_INT8:
        return v8::Integer::New (arg->v_int8);
    case GI_TYPE_TAG_UINT8:
        return v8::Integer::NewFromUnsigned (arg->v_uint8);
    case GI_TYPE_TAG_FLOAT:
        return v8::Number::New (arg->v_float);
    case GI_TYPE_TAG_DOUBLE:
        return v8::Number::New (arg->v_double);

    /* For 64-bit integer types, use a float. When JS and V8 adopt
     * bigger sized integer types, start using those instead. */
    case GI_TYPE_TAG_INT64:
        return v8::Number::New (arg->v_int64);
    case GI_TYPE_TAG_UINT64:
        return v8::Number::New (arg->v_uint64);

    case GI_TYPE_TAG_UNICHAR:
        {
            char data[7];
            int size = g_unichar_to_utf8 (arg->v_uint32, data);
            return v8::String::New (data, size);
        }

    case GI_TYPE_TAG_UTF8:
        if (arg->v_pointer)
            return v8::String::New ((char *) arg->v_pointer);
        else
            return v8::Null ();

    case GI_TYPE_TAG_INTERFACE:
        {
            GIBaseInfo *interface_info = g_type_info_get_interface (type_info);
            GIInfoType interface_type = g_base_info_get_type (interface_info);

            switch (interface_type) {
            case GI_INFO_TYPE_OBJECT:
                return WrapperFromGObject ((GObject *) arg->v_pointer);
            default:
                g_assert_not_reached ();
            }
        }
        break;

    default:
        g_assert_not_reached ();
    }
}

void V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, v8::Handle<v8::Value> value) {
    GITypeTag type_tag = g_type_info_get_tag (type_info);

    switch (type_tag) {
    case GI_TYPE_TAG_VOID:
        arg->v_pointer = NULL;
        break;
    case GI_TYPE_TAG_BOOLEAN:
        arg->v_boolean = value->BooleanValue ();
        break;
    case GI_TYPE_TAG_INT32:
        arg->v_int = value->Int32Value ();
        break;
    case GI_TYPE_TAG_UINT32:
        arg->v_uint = value->Uint32Value ();
        break;
    case GI_TYPE_TAG_INT64:
        arg->v_int64 = value->NumberValue ();
        break;
    case GI_TYPE_TAG_UINT64:
        arg->v_uint64 = value->NumberValue ();
        break;
    case GI_TYPE_TAG_FLOAT:
        arg->v_float = value->NumberValue ();
        break;
    case GI_TYPE_TAG_DOUBLE:
        arg->v_double = value->NumberValue ();
        break;

    case GI_TYPE_TAG_UTF8:
        {
            v8::String::Utf8Value str (value);
            const char *data = *str;
            arg->v_pointer = g_strdup (data);
        }
        break;

    case GI_TYPE_TAG_INTERFACE:
        {
            GIBaseInfo *interface_info = g_type_info_get_interface (type_info);
            GIInfoType interface_type = g_base_info_get_type (interface_info);

            switch (interface_type) {
            case GI_INFO_TYPE_OBJECT:
                arg->v_pointer = GObjectFromWrapper (value);
                break;
            default:
                g_assert_not_reached ();
            }

            g_base_info_unref (interface_info);
        }
        break;

    default:
        g_assert_not_reached ();
    }
}

void FreeGIArgument(GITypeInfo *type_info, GIArgument *arg) {
    GITypeTag type_tag = g_type_info_get_tag (type_info);

    switch (type_tag) {
    case GI_TYPE_TAG_UTF8:
        g_free (arg->v_pointer);
        break;
    default:
        break;
    }
}

void V8ToGValue(GValue *gvalue, v8::Handle<v8::Value> value) {
    if (G_VALUE_HOLDS_BOOLEAN (gvalue)) {
        g_value_set_boolean (gvalue, value->BooleanValue ());
    } else if (G_VALUE_HOLDS_INT (gvalue)) {
        g_value_set_int (gvalue, value->Int32Value ());
    } else if (G_VALUE_HOLDS_UINT (gvalue)) {
        g_value_set_uint (gvalue, value->Uint32Value ());
    } else if (G_VALUE_HOLDS_FLOAT (gvalue)) {
        g_value_set_float (gvalue, value->NumberValue ());
    } else if (G_VALUE_HOLDS_DOUBLE (gvalue)) {
        g_value_set_double (gvalue, value->NumberValue ());
    } else if (G_VALUE_HOLDS_STRING (gvalue)) {
        v8::String::Utf8Value str (value);
        const char *data = *str;
        g_value_set_string (gvalue, data);
    } else {
        g_assert_not_reached ();
    }
}

};
<commit_msg>value: Add support for arrays<commit_after>/*
 * Copyright (C) 2014 Endless Mobile
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * Written by:
 *     Jasper St. Pierre <jstpierre@mecheye.net>
 */

#include "value.h"
#include "gobject.h"

namespace GNodeJS {

v8::Handle<v8::Value> GIArgumentToV8(GITypeInfo *type_info, GIArgument *arg) {
    GITypeTag type_tag = g_type_info_get_tag (type_info);

    switch (type_tag) {
    case GI_TYPE_TAG_VOID:
        return v8::Undefined ();

    case GI_TYPE_TAG_BOOLEAN:
        if (arg->v_boolean)
            return v8::True ();
        else
            return v8::False ();

    case GI_TYPE_TAG_INT32:
        return v8::Integer::New (arg->v_int);
    case GI_TYPE_TAG_UINT32:
        return v8::Integer::NewFromUnsigned (arg->v_uint);
    case GI_TYPE_TAG_INT16:
        return v8::Integer::New (arg->v_int16);
    case GI_TYPE_TAG_UINT16:
        return v8::Integer::NewFromUnsigned (arg->v_uint16);
    case GI_TYPE_TAG_INT8:
        return v8::Integer::New (arg->v_int8);
    case GI_TYPE_TAG_UINT8:
        return v8::Integer::NewFromUnsigned (arg->v_uint8);
    case GI_TYPE_TAG_FLOAT:
        return v8::Number::New (arg->v_float);
    case GI_TYPE_TAG_DOUBLE:
        return v8::Number::New (arg->v_double);

    /* For 64-bit integer types, use a float. When JS and V8 adopt
     * bigger sized integer types, start using those instead. */
    case GI_TYPE_TAG_INT64:
        return v8::Number::New (arg->v_int64);
    case GI_TYPE_TAG_UINT64:
        return v8::Number::New (arg->v_uint64);

    case GI_TYPE_TAG_UNICHAR:
        {
            char data[7];
            int size = g_unichar_to_utf8 (arg->v_uint32, data);
            return v8::String::New (data, size);
        }

    case GI_TYPE_TAG_UTF8:
        if (arg->v_pointer)
            return v8::String::New ((char *) arg->v_pointer);
        else
            return v8::Null ();

    case GI_TYPE_TAG_INTERFACE:
        {
            GIBaseInfo *interface_info = g_type_info_get_interface (type_info);
            GIInfoType interface_type = g_base_info_get_type (interface_info);

            switch (interface_type) {
            case GI_INFO_TYPE_OBJECT:
                return WrapperFromGObject ((GObject *) arg->v_pointer);
            default:
                g_assert_not_reached ();
            }
        }
        break;

    default:
        g_assert_not_reached ();
    }
}

static GArray * V8ToGArray(GITypeInfo *type_info, v8::Handle<v8::Value> value) {
    if (!value->IsArray ()) {
        ThrowException (v8::Exception::TypeError (v8::String::New ("Not an array.")));
        return NULL;
    }

    v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast (value->ToObject ());
    GITypeInfo *elem_info = g_type_info_get_param_type (type_info, 0);

    int length = array->Length ();
    GArray *garray = g_array_sized_new (TRUE, FALSE, sizeof (GIArgument), length);
    for (int i = 0; i < length; i++) {
        v8::Local<v8::Value> value = array->Get (i);
        GIArgument arg;

        V8ToGIArgument (elem_info, &arg, value);
        g_array_append_val (garray, arg);
    }

    g_base_info_unref ((GIBaseInfo *) elem_info);
    return garray;
}

void V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, v8::Handle<v8::Value> value) {
    GITypeTag type_tag = g_type_info_get_tag (type_info);

    switch (type_tag) {
    case GI_TYPE_TAG_VOID:
        arg->v_pointer = NULL;
        break;
    case GI_TYPE_TAG_BOOLEAN:
        arg->v_boolean = value->BooleanValue ();
        break;
    case GI_TYPE_TAG_INT32:
        arg->v_int = value->Int32Value ();
        break;
    case GI_TYPE_TAG_UINT32:
        arg->v_uint = value->Uint32Value ();
        break;
    case GI_TYPE_TAG_INT64:
        arg->v_int64 = value->NumberValue ();
        break;
    case GI_TYPE_TAG_UINT64:
        arg->v_uint64 = value->NumberValue ();
        break;
    case GI_TYPE_TAG_FLOAT:
        arg->v_float = value->NumberValue ();
        break;
    case GI_TYPE_TAG_DOUBLE:
        arg->v_double = value->NumberValue ();
        break;

    case GI_TYPE_TAG_UTF8:
        {
            v8::String::Utf8Value str (value);
            const char *data = *str;
            arg->v_pointer = g_strdup (data);
        }
        break;

    case GI_TYPE_TAG_INTERFACE:
        {
            GIBaseInfo *interface_info = g_type_info_get_interface (type_info);
            GIInfoType interface_type = g_base_info_get_type (interface_info);

            switch (interface_type) {
            case GI_INFO_TYPE_OBJECT:
                arg->v_pointer = GObjectFromWrapper (value);
                break;
            default:
                g_assert_not_reached ();
            }

            g_base_info_unref (interface_info);
        }
        break;

    case GI_TYPE_TAG_ARRAY:
        {
            GIArrayType array_type = g_type_info_get_array_type (type_info);
            GArray *garray = V8ToGArray (type_info, value);

            switch (array_type) {
            case GI_ARRAY_TYPE_C:
                arg->v_pointer = g_array_free (garray, FALSE);
                break;
            case GI_ARRAY_TYPE_ARRAY:
                arg->v_pointer = garray;
                break;
            default:
                g_assert_not_reached ();
            }
        }
        break;

    default:
        g_assert_not_reached ();
    }
}

void FreeGIArgument(GITypeInfo *type_info, GIArgument *arg) {
    GITypeTag type_tag = g_type_info_get_tag (type_info);

    switch (type_tag) {
    case GI_TYPE_TAG_UTF8:
        g_free (arg->v_pointer);
        break;

    case GI_TYPE_TAG_ARRAY:
        {
            GIArrayType array_type = g_type_info_get_array_type (type_info);

            switch (array_type) {
            case GI_ARRAY_TYPE_C:
                g_free (arg->v_pointer);
                break;
            case GI_ARRAY_TYPE_ARRAY:
                g_array_free ((GArray *) arg->v_pointer, TRUE);
                break;
            default:
                g_assert_not_reached ();
            }
        }
        break;
    default:
        break;
    }
}

void V8ToGValue(GValue *gvalue, v8::Handle<v8::Value> value) {
    if (G_VALUE_HOLDS_BOOLEAN (gvalue)) {
        g_value_set_boolean (gvalue, value->BooleanValue ());
    } else if (G_VALUE_HOLDS_INT (gvalue)) {
        g_value_set_int (gvalue, value->Int32Value ());
    } else if (G_VALUE_HOLDS_UINT (gvalue)) {
        g_value_set_uint (gvalue, value->Uint32Value ());
    } else if (G_VALUE_HOLDS_FLOAT (gvalue)) {
        g_value_set_float (gvalue, value->NumberValue ());
    } else if (G_VALUE_HOLDS_DOUBLE (gvalue)) {
        g_value_set_double (gvalue, value->NumberValue ());
    } else if (G_VALUE_HOLDS_STRING (gvalue)) {
        v8::String::Utf8Value str (value);
        const char *data = *str;
        g_value_set_string (gvalue, data);
    } else {
        g_assert_not_reached ();
    }
}

};
<|endoftext|>


<commit_before>//===- InputFiles.cpp -----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "InputFiles.h"
#include "InputSection.h"
#include "Error.h"
#include "Symbols.h"
#include "llvm/ADT/STLExtras.h"

using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;

using namespace lld;
using namespace lld::elf2;

template <class ELFT> static uint16_t getEMachine(const ELFFileBase &B) {
  bool IsShared = isa<SharedFileBase>(B);
  if (IsShared)
    return cast<SharedFile<ELFT>>(B).getEMachine();
  return cast<ObjectFile<ELFT>>(B).getEMachine();
}

uint16_t ELFFileBase::getEMachine() const {
  switch (EKind) {
  case ELF32BEKind:
    return ::getEMachine<ELF32BE>(*this);
  case ELF32LEKind:
    return ::getEMachine<ELF32LE>(*this);
  case ELF64BEKind:
    return ::getEMachine<ELF64BE>(*this);
  case ELF64LEKind:
    return ::getEMachine<ELF64LE>(*this);
  }
  llvm_unreachable("Invalid kind");
}

bool ELFFileBase::isCompatibleWith(const ELFFileBase &Other) const {
  return getELFKind() == Other.getELFKind() &&
         getEMachine() == Other.getEMachine();
}

namespace {
class ECRAII {
  std::error_code EC;

public:
  std::error_code &getEC() { return EC; }
  ~ECRAII() { error(EC); }
};
}

template <class ELFT>
ELFData<ELFT>::ELFData(MemoryBufferRef MB)
    : ELFObj(MB.getBuffer(), ECRAII().getEC()) {}

template <class ELFT>
typename ELFData<ELFT>::Elf_Sym_Range
ELFData<ELFT>::getSymbolsHelper(bool Local) {
  if (!Symtab)
    return Elf_Sym_Range(nullptr, nullptr);
  Elf_Sym_Range Syms = ELFObj.symbols(Symtab);
  uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
  uint32_t FirstNonLocal = Symtab->sh_info;
  if (FirstNonLocal > NumSymbols)
    error("Invalid sh_info in symbol table");
  if (!Local)
    return llvm::make_range(Syms.begin() + FirstNonLocal, Syms.end());
  else
    // Skip over dummy symbol.
    return llvm::make_range(Syms.begin() + 1, Syms.begin() + FirstNonLocal);
}

template <class ELFT>
typename ELFData<ELFT>::Elf_Sym_Range ELFData<ELFT>::getNonLocalSymbols() {
  if (!Symtab)
    return Elf_Sym_Range(nullptr, nullptr);
  ErrorOr<StringRef> StringTableOrErr = ELFObj.getStringTableForSymtab(*Symtab);
  error(StringTableOrErr.getError());
  StringTable = *StringTableOrErr;
  return getSymbolsHelper(false);
}

template <class ELFT>
ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
    : ObjectFileBase(getStaticELFKind<ELFT>(), M), ELFData<ELFT>(M) {}

template <class ELFT>
typename ObjectFile<ELFT>::Elf_Sym_Range ObjectFile<ELFT>::getLocalSymbols() {
  return this->getSymbolsHelper(true);
}

template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
  // Read section and symbol tables.
  initializeSections();
  initializeSymbols();
}

template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSections() {
  uint64_t Size = this->ELFObj.getNumSections();
  Sections.resize(Size);
  unsigned I = 0;
  for (const Elf_Shdr &Sec : this->ELFObj.sections()) {
    switch (Sec.sh_type) {
    case SHT_SYMTAB:
      this->Symtab = &Sec;
      break;
    case SHT_SYMTAB_SHNDX: {
      ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable =
          this->ELFObj.getSHNDXTable(Sec);
      error(ErrorOrTable);
      SymtabSHNDX = *ErrorOrTable;
      break;
    }
    case SHT_STRTAB:
    case SHT_NULL:
      break;
    case SHT_RELA:
    case SHT_REL: {
      uint32_t RelocatedSectionIndex = Sec.sh_info;
      if (RelocatedSectionIndex >= Size)
        error("Invalid relocated section index");
      InputSection<ELFT> *RelocatedSection = Sections[RelocatedSectionIndex];
      if (!RelocatedSection)
        error("Unsupported relocation reference");
      RelocatedSection->RelocSections.push_back(&Sec);
      break;
    }
    default:
      Sections[I] = new (Alloc) InputSection<ELFT>(this, &Sec);
      break;
    }
    ++I;
  }
}

template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
  Elf_Sym_Range Syms = this->getNonLocalSymbols();
  uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
  SymbolBodies.reserve(NumSymbols);
  for (const Elf_Sym &Sym : Syms)
    SymbolBodies.push_back(createSymbolBody(this->StringTable, &Sym));
}

template <class ELFT>
SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
                                                     const Elf_Sym *Sym) {
  ErrorOr<StringRef> NameOrErr = Sym->getName(StringTable);
  error(NameOrErr.getError());
  StringRef Name = *NameOrErr;

  uint32_t SecIndex = Sym->st_shndx;
  switch (SecIndex) {
  case SHN_ABS:
    return new (Alloc) DefinedAbsolute<ELFT>(Name, *Sym);
  case SHN_UNDEF:
    return new (Alloc) Undefined<ELFT>(Name, *Sym);
  case SHN_COMMON:
    return new (Alloc) DefinedCommon<ELFT>(Name, *Sym);
  case SHN_XINDEX:
    SecIndex = this->ELFObj.getExtendedSymbolTableIndex(Sym, this->Symtab,
                                                        SymtabSHNDX);
    break;
  }

  if (SecIndex >= Sections.size() || (SecIndex != 0 && !Sections[SecIndex]))
    error("Invalid section index");

  switch (Sym->getBinding()) {
  default:
    error("unexpected binding");
  case STB_GLOBAL:
  case STB_WEAK:
    return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, *Sections[SecIndex]);
  }
}

void ArchiveFile::parse() {
  auto ArchiveOrErr = Archive::create(MB);
  error(ArchiveOrErr, "Failed to parse archive");
  File = std::move(*ArchiveOrErr);

  // Allocate a buffer for Lazy objects.
  size_t NumSyms = File->getNumberOfSymbols();
  LazySymbols.reserve(NumSyms);

  // Read the symbol table to construct Lazy objects.
  for (const Archive::Symbol &Sym : File->symbols())
    LazySymbols.emplace_back(this, Sym);
}

// Returns a buffer pointing to a member file containing a given symbol.
MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
  ErrorOr<Archive::child_iterator> ItOrErr = Sym->getMember();
  error(ItOrErr,
        Twine("Could not get the member for symbol ") + Sym->getName());
  Archive::child_iterator It = *ItOrErr;

  if (!Seen.insert(It->getChildOffset()).second)
    return MemoryBufferRef();

  ErrorOr<MemoryBufferRef> Ret = It->getMemoryBufferRef();
  error(Ret, Twine("Could not get the buffer for the member defining symbol ") +
                 Sym->getName());
  return *Ret;
}

template <class ELFT>
SharedFile<ELFT>::SharedFile(MemoryBufferRef M)
    : SharedFileBase(getStaticELFKind<ELFT>(), M), ELFData<ELFT>(M) {}

template <class ELFT> void SharedFile<ELFT>::parse() {
  for (const Elf_Shdr &Sec : this->ELFObj.sections()) {
    if (Sec.sh_type == SHT_DYNSYM) {
      this->Symtab = &Sec;
      break;
    }
  }

  Elf_Sym_Range Syms = this->getNonLocalSymbols();
  uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
  SymbolBodies.reserve(NumSymbols);
  for (const Elf_Sym &Sym : Syms) {
    if (Sym.isUndefined())
      continue;

    ErrorOr<StringRef> NameOrErr = Sym.getName(this->StringTable);
    error(NameOrErr.getError());
    StringRef Name = *NameOrErr;

    SymbolBodies.emplace_back(Name, Sym);
  }
}

namespace lld {
namespace elf2 {

template class elf2::ObjectFile<llvm::object::ELF32LE>;
template class elf2::ObjectFile<llvm::object::ELF32BE>;
template class elf2::ObjectFile<llvm::object::ELF64LE>;
template class elf2::ObjectFile<llvm::object::ELF64BE>;

template class elf2::SharedFile<llvm::object::ELF32LE>;
template class elf2::SharedFile<llvm::object::ELF32BE>;
template class elf2::SharedFile<llvm::object::ELF64LE>;
template class elf2::SharedFile<llvm::object::ELF64BE>;
}
}
<commit_msg>Remove `else` after `return`.<commit_after>//===- InputFiles.cpp -----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "InputFiles.h"
#include "InputSection.h"
#include "Error.h"
#include "Symbols.h"
#include "llvm/ADT/STLExtras.h"

using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;

using namespace lld;
using namespace lld::elf2;

template <class ELFT> static uint16_t getEMachine(const ELFFileBase &B) {
  bool IsShared = isa<SharedFileBase>(B);
  if (IsShared)
    return cast<SharedFile<ELFT>>(B).getEMachine();
  return cast<ObjectFile<ELFT>>(B).getEMachine();
}

uint16_t ELFFileBase::getEMachine() const {
  switch (EKind) {
  case ELF32BEKind:
    return ::getEMachine<ELF32BE>(*this);
  case ELF32LEKind:
    return ::getEMachine<ELF32LE>(*this);
  case ELF64BEKind:
    return ::getEMachine<ELF64BE>(*this);
  case ELF64LEKind:
    return ::getEMachine<ELF64LE>(*this);
  }
  llvm_unreachable("Invalid kind");
}

bool ELFFileBase::isCompatibleWith(const ELFFileBase &Other) const {
  return getELFKind() == Other.getELFKind() &&
         getEMachine() == Other.getEMachine();
}

namespace {
class ECRAII {
  std::error_code EC;

public:
  std::error_code &getEC() { return EC; }
  ~ECRAII() { error(EC); }
};
}

template <class ELFT>
ELFData<ELFT>::ELFData(MemoryBufferRef MB)
    : ELFObj(MB.getBuffer(), ECRAII().getEC()) {}

template <class ELFT>
typename ELFData<ELFT>::Elf_Sym_Range
ELFData<ELFT>::getSymbolsHelper(bool Local) {
  if (!Symtab)
    return Elf_Sym_Range(nullptr, nullptr);
  Elf_Sym_Range Syms = ELFObj.symbols(Symtab);
  uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
  uint32_t FirstNonLocal = Symtab->sh_info;
  if (FirstNonLocal > NumSymbols)
    error("Invalid sh_info in symbol table");
  if (!Local)
    return make_range(Syms.begin() + FirstNonLocal, Syms.end());
  // +1 to skip over dummy symbol.
  return make_range(Syms.begin() + 1, Syms.begin() + FirstNonLocal);
}

template <class ELFT>
typename ELFData<ELFT>::Elf_Sym_Range ELFData<ELFT>::getNonLocalSymbols() {
  if (!Symtab)
    return Elf_Sym_Range(nullptr, nullptr);
  ErrorOr<StringRef> StringTableOrErr = ELFObj.getStringTableForSymtab(*Symtab);
  error(StringTableOrErr.getError());
  StringTable = *StringTableOrErr;
  return getSymbolsHelper(false);
}

template <class ELFT>
ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
    : ObjectFileBase(getStaticELFKind<ELFT>(), M), ELFData<ELFT>(M) {}

template <class ELFT>
typename ObjectFile<ELFT>::Elf_Sym_Range ObjectFile<ELFT>::getLocalSymbols() {
  return this->getSymbolsHelper(true);
}

template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
  // Read section and symbol tables.
  initializeSections();
  initializeSymbols();
}

template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSections() {
  uint64_t Size = this->ELFObj.getNumSections();
  Sections.resize(Size);
  unsigned I = 0;
  for (const Elf_Shdr &Sec : this->ELFObj.sections()) {
    switch (Sec.sh_type) {
    case SHT_SYMTAB:
      this->Symtab = &Sec;
      break;
    case SHT_SYMTAB_SHNDX: {
      ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable =
          this->ELFObj.getSHNDXTable(Sec);
      error(ErrorOrTable);
      SymtabSHNDX = *ErrorOrTable;
      break;
    }
    case SHT_STRTAB:
    case SHT_NULL:
      break;
    case SHT_RELA:
    case SHT_REL: {
      uint32_t RelocatedSectionIndex = Sec.sh_info;
      if (RelocatedSectionIndex >= Size)
        error("Invalid relocated section index");
      InputSection<ELFT> *RelocatedSection = Sections[RelocatedSectionIndex];
      if (!RelocatedSection)
        error("Unsupported relocation reference");
      RelocatedSection->RelocSections.push_back(&Sec);
      break;
    }
    default:
      Sections[I] = new (Alloc) InputSection<ELFT>(this, &Sec);
      break;
    }
    ++I;
  }
}

template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
  Elf_Sym_Range Syms = this->getNonLocalSymbols();
  uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
  SymbolBodies.reserve(NumSymbols);
  for (const Elf_Sym &Sym : Syms)
    SymbolBodies.push_back(createSymbolBody(this->StringTable, &Sym));
}

template <class ELFT>
SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
                                                     const Elf_Sym *Sym) {
  ErrorOr<StringRef> NameOrErr = Sym->getName(StringTable);
  error(NameOrErr.getError());
  StringRef Name = *NameOrErr;

  uint32_t SecIndex = Sym->st_shndx;
  switch (SecIndex) {
  case SHN_ABS:
    return new (Alloc) DefinedAbsolute<ELFT>(Name, *Sym);
  case SHN_UNDEF:
    return new (Alloc) Undefined<ELFT>(Name, *Sym);
  case SHN_COMMON:
    return new (Alloc) DefinedCommon<ELFT>(Name, *Sym);
  case SHN_XINDEX:
    SecIndex = this->ELFObj.getExtendedSymbolTableIndex(Sym, this->Symtab,
                                                        SymtabSHNDX);
    break;
  }

  if (SecIndex >= Sections.size() || (SecIndex != 0 && !Sections[SecIndex]))
    error("Invalid section index");

  switch (Sym->getBinding()) {
  default:
    error("unexpected binding");
  case STB_GLOBAL:
  case STB_WEAK:
    return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, *Sections[SecIndex]);
  }
}

void ArchiveFile::parse() {
  auto ArchiveOrErr = Archive::create(MB);
  error(ArchiveOrErr, "Failed to parse archive");
  File = std::move(*ArchiveOrErr);

  // Allocate a buffer for Lazy objects.
  size_t NumSyms = File->getNumberOfSymbols();
  LazySymbols.reserve(NumSyms);

  // Read the symbol table to construct Lazy objects.
  for (const Archive::Symbol &Sym : File->symbols())
    LazySymbols.emplace_back(this, Sym);
}

// Returns a buffer pointing to a member file containing a given symbol.
MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
  ErrorOr<Archive::child_iterator> ItOrErr = Sym->getMember();
  error(ItOrErr,
        Twine("Could not get the member for symbol ") + Sym->getName());
  Archive::child_iterator It = *ItOrErr;

  if (!Seen.insert(It->getChildOffset()).second)
    return MemoryBufferRef();

  ErrorOr<MemoryBufferRef> Ret = It->getMemoryBufferRef();
  error(Ret, Twine("Could not get the buffer for the member defining symbol ") +
                 Sym->getName());
  return *Ret;
}

template <class ELFT>
SharedFile<ELFT>::SharedFile(MemoryBufferRef M)
    : SharedFileBase(getStaticELFKind<ELFT>(), M), ELFData<ELFT>(M) {}

template <class ELFT> void SharedFile<ELFT>::parse() {
  for (const Elf_Shdr &Sec : this->ELFObj.sections()) {
    if (Sec.sh_type == SHT_DYNSYM) {
      this->Symtab = &Sec;
      break;
    }
  }

  Elf_Sym_Range Syms = this->getNonLocalSymbols();
  uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
  SymbolBodies.reserve(NumSymbols);
  for (const Elf_Sym &Sym : Syms) {
    if (Sym.isUndefined())
      continue;

    ErrorOr<StringRef> NameOrErr = Sym.getName(this->StringTable);
    error(NameOrErr.getError());
    StringRef Name = *NameOrErr;

    SymbolBodies.emplace_back(Name, Sym);
  }
}

namespace lld {
namespace elf2 {

template class elf2::ObjectFile<llvm::object::ELF32LE>;
template class elf2::ObjectFile<llvm::object::ELF32BE>;
template class elf2::ObjectFile<llvm::object::ELF64LE>;
template class elf2::ObjectFile<llvm::object::ELF64BE>;

template class elf2::SharedFile<llvm::object::ELF32LE>;
template class elf2::SharedFile<llvm::object::ELF32BE>;
template class elf2::SharedFile<llvm::object::ELF64LE>;
template class elf2::SharedFile<llvm::object::ELF64BE>;
}
}
<|endoftext|>


<commit_before>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

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

*/

#include "command.h"
#include "progressbar.h"
#include "math/vector.h"
#include "math/matrix.h"
#include "math/rng.h"
#include "point.h"
#include "dwi/directions/file.h"
#include "file/ofstream.h"

#include <array>
#include <random>
#include <algorithm>

using namespace MR;
using namespace App;

void usage () {

DESCRIPTION
  + "splice or merge sets of directions over multiple shells into a single set, "
    "in such a way as to maintain near-optimality upon truncation.";

ARGUMENTS
  + Argument ("subsets", "the number of subsets (phase-encode directions) per b-value").type_integer(1,4,10000)
  + Argument ("bvalue files", "the b-value and sets of corresponding files, in order").type_text().allow_multiple()
  + Argument ("out", "the output directions file, with each row listing "
      "the X Y Z gradient directions, the b-value, and an index representing "
      "the phase encode direction").type_file_out();
}

typedef double value_type;
typedef std::array<value_type,3> Direction;
typedef std::vector<Direction> DirectionSet;

struct OutDir {
  Direction d;
  size_t b;
  size_t pe;
};

inline std::ostream& operator<< (std::ostream& stream, const OutDir& d) {
  stream << "[ " << d.d << "], " << d.b << ", " << d.pe << " ]";
  return stream;
}

void run ()
{
  size_t num_subsets = argument[0];

  std::vector<std::vector<DirectionSet>> dirs;
  std::vector<value_type> bvalue ((argument.size() - 2) / (1+num_subsets));
  INFO ("expecting " + str(bvalue.size()) + " b-values");
  if (bvalue.size()*(1+num_subsets) + 2 != argument.size())
    throw Exception ("inconsistent number of arguments");

  // read them in:
  size_t current = 1, nb = 0;
  while (current < argument.size()-1) {
    bvalue[nb] = to<value_type> (argument[current++]);
    std::vector<DirectionSet> d;
    for (size_t i = 0; i < num_subsets; ++i) {
      auto m = DWI::Directions::load_cartesian<value_type> (argument[current++]);
      DirectionSet set;
      for (size_t r = 0; r < m.rows(); ++r)
        set.push_back ({ { m(r,0), m(r,1), m(r,2) } });
      d.push_back (set);
    }
    INFO ("found b = " + str(bvalue[nb]) + ", " +
        str ([&]{ std::vector<size_t> s; for (auto& n : d) s.push_back (n.size()); return s; }()) + " volumes");

    dirs.push_back (d);
    ++nb;
  }

  size_t total = [&]{ size_t n = 0; for (auto& d : dirs) for (auto& m : d) n += m.size(); return n; }();
  INFO ("found total of " + str(total) + " volumes") ;

  // pick random direction from first direction set:
  std::random_device rd;
  std::mt19937 rng (rd());
  size_t first = std::uniform_int_distribution<size_t> (0, dirs[0][0].size()-1)(rng);

  std::vector<OutDir> merged;

  auto push = [&](size_t b, size_t p, size_t n)
  {
    merged.push_back ({ { { dirs[b][p][n][0], dirs[b][p][n][1], dirs[b][p][n][2] } }, b, p });
    dirs[b][p].erase (dirs[b][p].begin()+n);
  };

  auto energy_pair = [](const Direction& a, const Direction& b)
  {
    // use combination of mono- and bi-polar electrostatic repulsion models
    // to ensure adequate coverage of eddy-current space as well as
    // orientation space. Use a moderate bias, favouring the bipolar model.
    return 1.2 / (
        Math::pow2 (b[0] - a[0]) +
        Math::pow2 (b[1] - a[1]) +
        Math::pow2 (b[2] - a[2])
        ) + 1.0 / (
        Math::pow2 (b[0] + a[0]) +
        Math::pow2 (b[1] + a[1]) +
        Math::pow2 (b[2] + a[2])
        );
  };

  auto energy = [&](size_t b, size_t p, size_t n)
  {
    value_type E = 0.0;
    for (auto& d : merged)
      if (d.b == b)
        E += energy_pair (d.d, dirs[b][p][n]);
    return E;
  };

  auto find_lowest_energy_direction = [&](size_t b, size_t p)
  {
    size_t best = 0;
    value_type bestE = std::numeric_limits<value_type>::max();
    for (size_t n = 0; n < dirs[b][p].size(); ++n) {
      value_type E = energy (b, p, n);
      if (E < bestE) {
        bestE = E;
        best = n;
      }
    }
    return best;
  };

  std::vector<float> fraction;
  for (auto& d : dirs) {
    size_t n = 0;
    for (auto& m : d)
      n += m.size();
    fraction.push_back (float (n) / float (total));
  };

  push (0, 0, first);

  std::vector<size_t> counts (bvalue.size(), 0);
  ++counts[0];

  auto num_for_b = [&](size_t b) {
    size_t n = 0;
    for (auto& d : merged)
      if (d.b == b)
        ++n;
    return n;
  };

  size_t nPE = num_subsets > 1 ? 1 : 0;
  while (merged.size() < total) {
    // find shell with shortfall in numbers:
    size_t b = 0, n;
    value_type fraction_diff = std::numeric_limits<value_type>::max();
    for (n = 0; n < bvalue.size(); ++n) {
      value_type f_diff = float(num_for_b(n)) / float (merged.size()) - fraction[n];
      if (f_diff < fraction_diff && dirs[n][nPE].size()) {
        fraction_diff = f_diff;
        b = n;
      }
    }

    // find most distant direction for that shell & in the current PE direction:
    n = find_lowest_energy_direction (b, nPE);
    if (dirs[b][nPE].size())
      push (b, nPE, n);

    // update PE direction
    ++nPE;
    if (nPE >= num_subsets)
      nPE = 0;
  }

  // write-out:

  File::OFStream out (argument[argument.size()-1]);
  for (auto& d : merged)
    out << MR::printf ("%#10f %#10f %#10f %5d %3d\n",
        float (d.d[0]), float (d.d[1]), float (d.d[2]),
        int (bvalue[d.b]), int (d.pe+1));

}

<commit_msg>dirmerge: add warning if merging cannot be done as expected<commit_after>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

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

*/

#include "command.h"
#include "progressbar.h"
#include "math/vector.h"
#include "math/matrix.h"
#include "math/rng.h"
#include "point.h"
#include "dwi/directions/file.h"
#include "file/ofstream.h"

#include <array>
#include <random>
#include <algorithm>

using namespace MR;
using namespace App;

void usage () {

DESCRIPTION
  + "splice or merge sets of directions over multiple shells into a single set, "
    "in such a way as to maintain near-optimality upon truncation.";

ARGUMENTS
  + Argument ("subsets", "the number of subsets (phase-encode directions) per b-value").type_integer(1,4,10000)
  + Argument ("bvalue files", "the b-value and sets of corresponding files, in order").type_text().allow_multiple()
  + Argument ("out", "the output directions file, with each row listing "
      "the X Y Z gradient directions, the b-value, and an index representing "
      "the phase encode direction").type_file_out();
}

typedef double value_type;
typedef std::array<value_type,3> Direction;
typedef std::vector<Direction> DirectionSet;

struct OutDir {
  Direction d;
  size_t b;
  size_t pe;
};

inline std::ostream& operator<< (std::ostream& stream, const OutDir& d) {
  stream << "[ " << d.d << "], " << d.b << ", " << d.pe << " ]";
  return stream;
}

void run ()
{
  size_t num_subsets = argument[0];

  std::vector<std::vector<DirectionSet>> dirs;
  std::vector<value_type> bvalue ((argument.size() - 2) / (1+num_subsets));
  INFO ("expecting " + str(bvalue.size()) + " b-values");
  if (bvalue.size()*(1+num_subsets) + 2 != argument.size())
    throw Exception ("inconsistent number of arguments");

  // read them in:
  size_t current = 1, nb = 0;
  while (current < argument.size()-1) {
    bvalue[nb] = to<value_type> (argument[current++]);
    std::vector<DirectionSet> d;
    for (size_t i = 0; i < num_subsets; ++i) {
      auto m = DWI::Directions::load_cartesian<value_type> (argument[current++]);
      DirectionSet set;
      for (size_t r = 0; r < m.rows(); ++r)
        set.push_back ({ { m(r,0), m(r,1), m(r,2) } });
      d.push_back (set);
    }
    INFO ("found b = " + str(bvalue[nb]) + ", " +
        str ([&]{ std::vector<size_t> s; for (auto& n : d) s.push_back (n.size()); return s; }()) + " volumes");

    dirs.push_back (d);
    ++nb;
  }

  size_t total = [&]{ size_t n = 0; for (auto& d : dirs) for (auto& m : d) n += m.size(); return n; }();
  INFO ("found total of " + str(total) + " volumes") ;

  // pick random direction from first direction set:
  std::random_device rd;
  std::mt19937 rng (rd());
  size_t first = std::uniform_int_distribution<size_t> (0, dirs[0][0].size()-1)(rng);

  std::vector<OutDir> merged;

  auto push = [&](size_t b, size_t p, size_t n)
  {
    merged.push_back ({ { { dirs[b][p][n][0], dirs[b][p][n][1], dirs[b][p][n][2] } }, b, p });
    dirs[b][p].erase (dirs[b][p].begin()+n);
  };

  auto energy_pair = [](const Direction& a, const Direction& b)
  {
    // use combination of mono- and bi-polar electrostatic repulsion models
    // to ensure adequate coverage of eddy-current space as well as
    // orientation space. Use a moderate bias, favouring the bipolar model.
    return 1.2 / (
        Math::pow2 (b[0] - a[0]) +
        Math::pow2 (b[1] - a[1]) +
        Math::pow2 (b[2] - a[2])
        ) + 1.0 / (
        Math::pow2 (b[0] + a[0]) +
        Math::pow2 (b[1] + a[1]) +
        Math::pow2 (b[2] + a[2])
        );
  };

  auto energy = [&](size_t b, size_t p, size_t n)
  {
    value_type E = 0.0;
    for (auto& d : merged)
      if (d.b == b)
        E += energy_pair (d.d, dirs[b][p][n]);
    return E;
  };

  auto find_lowest_energy_direction = [&](size_t b, size_t p)
  {
    size_t best = 0;
    value_type bestE = std::numeric_limits<value_type>::max();
    for (size_t n = 0; n < dirs[b][p].size(); ++n) {
      value_type E = energy (b, p, n);
      if (E < bestE) {
        bestE = E;
        best = n;
      }
    }
    return best;
  };

  std::vector<float> fraction;
  for (auto& d : dirs) {
    size_t n = 0;
    for (auto& m : d)
      n += m.size();
    fraction.push_back (float (n) / float (total));
  };

  push (0, 0, first);

  std::vector<size_t> counts (bvalue.size(), 0);
  ++counts[0];

  auto num_for_b = [&](size_t b) {
    size_t n = 0;
    for (auto& d : merged)
      if (d.b == b)
        ++n;
    return n;
  };

  size_t nPE = num_subsets > 1 ? 1 : 0;
  while (merged.size() < total) {
    // find shell with shortfall in numbers:
    size_t b = 0, n;
    value_type fraction_diff = std::numeric_limits<value_type>::max();
    for (n = 0; n < bvalue.size(); ++n) {
      value_type f_diff = float(num_for_b(n)) / float (merged.size()) - fraction[n];
      if (f_diff < fraction_diff && dirs[n][nPE].size()) {
        fraction_diff = f_diff;
        b = n;
      }
    }

    // find most distant direction for that shell & in the current PE direction:
    n = find_lowest_energy_direction (b, nPE);
    if (dirs[b][nPE].size())
      push (b, nPE, n);
    else
      WARN ("no directions remaining in b=" + str (bvalue[b]) + " shell for PE direction " + str(n) + " - PE directions will not cycle through perfectly");

    // update PE direction
    ++nPE;
    if (nPE >= num_subsets)
      nPE = 0;
  }

  // write-out:

  File::OFStream out (argument[argument.size()-1]);
  for (auto& d : merged)
    out << MR::printf ("%#10f %#10f %#10f %5d %3d\n",
        float (d.d[0]), float (d.d[1]), float (d.d[2]),
        int (bvalue[d.b]), int (d.pe+1));

}

<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
$Log$
Revision 1.4  2001/11/27 13:13:07  morsch
Maximum lifetime for long-lived particles to be put on the stack is parameter.
It can be set via SetMaximumLifetime(..).

Revision 1.3  2001/10/16 08:48:56  morsch
Common vertex related code moved to base class AliGenerator.

Revision 1.2  2001/10/15 08:15:51  morsch
Event vertex and vertex truncation setting moved into AliMC.

Revision 1.1  2001/07/13 10:56:00  morsch
AliGenMC base class for AliGenParam and AliGenPythia commonalities.

*/

#include "AliGenMC.h"
#include "AliPDG.h"
#include <TParticle.h>

 ClassImp(AliGenMC)

AliGenMC::AliGenMC()
                 :AliGenerator()
{
// Default Constructor
    SetCutOnChild();
    SetChildMomentumRange();
    SetChildPtRange();
    SetChildPhiRange();
    SetChildThetaRange();
    SetChildYRange();
    SetMaximumLifetime();
}

AliGenMC::AliGenMC(Int_t npart)
                 :AliGenerator(npart)
{
//  Constructor
    SetCutOnChild();
    SetChildMomentumRange();
    SetChildPtRange();
    SetChildPhiRange();
    SetChildThetaRange();
    SetChildYRange();
//
    fParentSelect.Set(8);
    fChildSelect.Set(8);
    for (Int_t i=0; i<8; i++) fParentSelect[i]=fChildSelect[i]=0;
    SetMaximumLifetime();
}

AliGenMC::AliGenMC(const AliGenMC & mc)
{
// copy constructor
}

AliGenMC::~AliGenMC()
{
// Destructor
}

void AliGenMC::Init()
{
//
//  Initialization
    switch (fForceDecay) {
    case kSemiElectronic:
    case kDiElectron:
    case kBJpsiDiElectron:
    case kBPsiPrimeDiElectron:
	fChildSelect[0] = kElectron;
	break;
    case kSemiMuonic:
    case kDiMuon:
    case kBJpsiDiMuon:
    case kBPsiPrimeDiMuon:
    case kPiToMu:
    case kKaToMu:
	fChildSelect[0]=kMuonMinus;
	break;
    case kHadronicD:
	fChildSelect[0]=kPiPlus;
	fChildSelect[1]=kKPlus;
	break;
    case kAll:
    case kNoDecay:
	break;
    }
}

Bool_t AliGenMC::ParentSelected(Int_t ip)
{
// True if particle is in list of parent particles to be selected
    for (Int_t i=0; i<8; i++)
    {
	if (fParentSelect[i]==ip) return kTRUE;
    }
    return kFALSE;
}

Bool_t AliGenMC::ChildSelected(Int_t ip)
{
// True if particle is in list of decay products to be selected
    for (Int_t i=0; i<5; i++)
    {
	if (fChildSelect[i]==ip) return kTRUE;
    }
    return kFALSE;
}

Bool_t AliGenMC::KinematicSelection(TParticle *particle, Int_t flag)
{
// Perform kinematic selection
    Float_t px    = particle->Px();
    Float_t py    = particle->Py();
    Float_t pz    = particle->Pz();
    Float_t  e    = particle->Energy();
    Float_t pt    = particle->Pt();
    Float_t p     = particle->P();
    Float_t theta = particle->Theta();
    Float_t mass  = particle->GetMass();
    Float_t mt2   = pt * pt + mass * mass;

    Float_t phi   = Float_t(TMath::ATan2(Double_t(py),Double_t(px)));
    Double_t y, y0;

    if (TMath::Abs(pz) != e) {
	y = 0.5*TMath::Log((e+pz)/(e-pz));
    } else {
	y = 1.e10;
    }

    if (mt2) {
	y0 = 0.5*TMath::Log((e+TMath::Abs(pz))*(e+TMath::Abs(pz))/mt2);
    } else {
	if (TMath::Abs(y) < 1.e10) {
	    y0 = y;
	} else {
	    y0 = 1.e10;
	}
    }

    y = (pz < 0) ? -y0 : y0;

    if (flag == 0) {
//
// Primary particle cuts
//
//  transverse momentum cut
	if (pt > fPtMax || pt < fPtMin) {
//	    printf("\n failed pt cut %f %f %f \n",pt,fPtMin,fPtMax);
	    return kFALSE;
	}
//
// momentum cut
	if (p > fPMax || p < fPMin) {
//	    printf("\n failed p cut %f %f %f \n",p,fPMin,fPMax);
	    return kFALSE;
	}
//
// theta cut
	if (theta > fThetaMax || theta < fThetaMin) {
//	    printf("\n failed theta cut %f %f %f \n",theta,fThetaMin,fThetaMax);
	    return kFALSE;
	}
//
// rapidity cut
	if (y > fYMax || y < fYMin) {
//	    printf("\n failed y cut %f %f %f \n",y,fYMin,fYMax);
	    return kFALSE;
	}
//
// phi cut
	if (phi > fPhiMax || phi < fPhiMin) {
//	    printf("\n failed phi cut %f %f %f \n",phi,fPhiMin,fPhiMax);
	    return kFALSE;
	}
    } else {
//
// Decay product cuts
//
//  transverse momentum cut
	if (pt > fChildPtMax || pt < fChildPtMin) {
//	    printf("\n failed pt cut %f %f %f \n",pt,fChildPtMin,fChildPtMax);
	    return kFALSE;
	}
//
// momentum cut
	if (p > fChildPMax || p < fChildPMin) {
//	    printf("\n failed p cut %f %f %f \n",p,fChildPMin,fChildPMax);
	    return kFALSE;
	}
//
// theta cut
	if (theta > fChildThetaMax || theta < fChildThetaMin) {
//	    printf("\n failed theta cut %f %f %f \n",theta,fChildThetaMin,fChildThetaMax);
	    return kFALSE;
	}
//
// rapidity cut
	if (y > fChildYMax || y < fChildYMin) {
//	    printf("\n failed y cut %f %f %f \n",y,fChildYMin,fChildYMax);
	    return kFALSE;
	}
//
// phi cut
	if (phi > fChildPhiMax || phi < fChildPhiMin) {
//	    printf("\n failed phi cut %f %f %f \n",phi,fChildPhiMin,fChildPhiMax);
	    return kFALSE;
	}
    }

    return kTRUE;
}

Int_t AliGenMC::CheckPDGCode(Int_t pdgcode)
{
//
//  If the particle is in a diffractive state, then take action accordingly
  switch (pdgcode) {
  case 91:
    return 92;
  case 110:
    //rho_diff0 -- difficult to translate, return rho0
    return 113;
  case 210:
    //pi_diffr+ -- change to pi+
    return 211;
  case 220:
    //omega_di0 -- change to omega0
    return 223;
  case 330:
    //phi_diff0 -- return phi0
    return 333;
  case 440:
    //J/psi_di0 -- return J/psi
    return 443;
  case 2110:
    //n_diffr -- return neutron
    return 2112;
  case 2210:
    //p_diffr+ -- return proton
    return 2212;
  }
  //non diffractive state -- return code unchanged
  return pdgcode;
}

AliGenMC& AliGenMC::operator=(const  AliGenMC& rhs)
{
// Assignment operator
    return *this;
}

<commit_msg>Saver calculation of rapdity.<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
$Log$
Revision 1.5  2002/03/12 17:02:20  morsch
Change in calculation of rapidity, include case in which numerically e == pz.

Revision 1.4  2001/11/27 13:13:07  morsch
Maximum lifetime for long-lived particles to be put on the stack is parameter.
It can be set via SetMaximumLifetime(..).

Revision 1.3  2001/10/16 08:48:56  morsch
Common vertex related code moved to base class AliGenerator.

Revision 1.2  2001/10/15 08:15:51  morsch
Event vertex and vertex truncation setting moved into AliMC.

Revision 1.1  2001/07/13 10:56:00  morsch
AliGenMC base class for AliGenParam and AliGenPythia commonalities.

*/

#include "AliGenMC.h"
#include "AliPDG.h"
#include <TParticle.h>

 ClassImp(AliGenMC)

AliGenMC::AliGenMC()
                 :AliGenerator()
{
// Default Constructor
    SetCutOnChild();
    SetChildMomentumRange();
    SetChildPtRange();
    SetChildPhiRange();
    SetChildThetaRange();
    SetChildYRange();
    SetMaximumLifetime();
}

AliGenMC::AliGenMC(Int_t npart)
                 :AliGenerator(npart)
{
//  Constructor
    SetCutOnChild();
    SetChildMomentumRange();
    SetChildPtRange();
    SetChildPhiRange();
    SetChildThetaRange();
    SetChildYRange();
//
    fParentSelect.Set(8);
    fChildSelect.Set(8);
    for (Int_t i=0; i<8; i++) fParentSelect[i]=fChildSelect[i]=0;
    SetMaximumLifetime();
}

AliGenMC::AliGenMC(const AliGenMC & mc)
{
// copy constructor
}

AliGenMC::~AliGenMC()
{
// Destructor
}

void AliGenMC::Init()
{
//
//  Initialization
    switch (fForceDecay) {
    case kSemiElectronic:
    case kDiElectron:
    case kBJpsiDiElectron:
    case kBPsiPrimeDiElectron:
	fChildSelect[0] = kElectron;
	break;
    case kSemiMuonic:
    case kDiMuon:
    case kBJpsiDiMuon:
    case kBPsiPrimeDiMuon:
    case kPiToMu:
    case kKaToMu:
	fChildSelect[0]=kMuonMinus;
	break;
    case kHadronicD:
	fChildSelect[0]=kPiPlus;
	fChildSelect[1]=kKPlus;
	break;
    case kAll:
    case kNoDecay:
	break;
    }
}

Bool_t AliGenMC::ParentSelected(Int_t ip)
{
// True if particle is in list of parent particles to be selected
    for (Int_t i=0; i<8; i++)
    {
	if (fParentSelect[i]==ip) return kTRUE;
    }
    return kFALSE;
}

Bool_t AliGenMC::ChildSelected(Int_t ip)
{
// True if particle is in list of decay products to be selected
    for (Int_t i=0; i<5; i++)
    {
	if (fChildSelect[i]==ip) return kTRUE;
    }
    return kFALSE;
}

Bool_t AliGenMC::KinematicSelection(TParticle *particle, Int_t flag)
{
// Perform kinematic selection
    Float_t px    = particle->Px();
    Float_t py    = particle->Py();
    Float_t pz    = particle->Pz();
    Float_t  e    = particle->Energy();
    Float_t pt    = particle->Pt();
    Float_t p     = particle->P();
    Float_t theta = particle->Theta();
    Float_t mass  = particle->GetMass();
    Float_t mt2   = pt * pt + mass * mass;

    Float_t phi   = Float_t(TMath::ATan2(Double_t(py),Double_t(px)));
    Double_t y, y0;

    if (TMath::Abs(pz) <  e) {
	y = 0.5*TMath::Log((e+pz)/(e-pz));
    } else {
	y = 1.e10;
    }

    if (mt2) {
	y0 = 0.5*TMath::Log((e+TMath::Abs(pz))*(e+TMath::Abs(pz))/mt2);
    } else {
	if (TMath::Abs(y) < 1.e10) {
	    y0 = y;
	} else {
	    y0 = 1.e10;
	}
    }

    y = (pz < 0) ? -y0 : y0;

    if (flag == 0) {
//
// Primary particle cuts
//
//  transverse momentum cut
	if (pt > fPtMax || pt < fPtMin) {
//	    printf("\n failed pt cut %f %f %f \n",pt,fPtMin,fPtMax);
	    return kFALSE;
	}
//
// momentum cut
	if (p > fPMax || p < fPMin) {
//	    printf("\n failed p cut %f %f %f \n",p,fPMin,fPMax);
	    return kFALSE;
	}
//
// theta cut
	if (theta > fThetaMax || theta < fThetaMin) {
//	    printf("\n failed theta cut %f %f %f \n",theta,fThetaMin,fThetaMax);
	    return kFALSE;
	}
//
// rapidity cut
	if (y > fYMax || y < fYMin) {
//	    printf("\n failed y cut %f %f %f \n",y,fYMin,fYMax);
	    return kFALSE;
	}
//
// phi cut
	if (phi > fPhiMax || phi < fPhiMin) {
//	    printf("\n failed phi cut %f %f %f \n",phi,fPhiMin,fPhiMax);
	    return kFALSE;
	}
    } else {
//
// Decay product cuts
//
//  transverse momentum cut
	if (pt > fChildPtMax || pt < fChildPtMin) {
//	    printf("\n failed pt cut %f %f %f \n",pt,fChildPtMin,fChildPtMax);
	    return kFALSE;
	}
//
// momentum cut
	if (p > fChildPMax || p < fChildPMin) {
//	    printf("\n failed p cut %f %f %f \n",p,fChildPMin,fChildPMax);
	    return kFALSE;
	}
//
// theta cut
	if (theta > fChildThetaMax || theta < fChildThetaMin) {
//	    printf("\n failed theta cut %f %f %f \n",theta,fChildThetaMin,fChildThetaMax);
	    return kFALSE;
	}
//
// rapidity cut
	if (y > fChildYMax || y < fChildYMin) {
//	    printf("\n failed y cut %f %f %f \n",y,fChildYMin,fChildYMax);
	    return kFALSE;
	}
//
// phi cut
	if (phi > fChildPhiMax || phi < fChildPhiMin) {
//	    printf("\n failed phi cut %f %f %f \n",phi,fChildPhiMin,fChildPhiMax);
	    return kFALSE;
	}
    }

    return kTRUE;
}

Int_t AliGenMC::CheckPDGCode(Int_t pdgcode)
{
//
//  If the particle is in a diffractive state, then take action accordingly
  switch (pdgcode) {
  case 91:
    return 92;
  case 110:
    //rho_diff0 -- difficult to translate, return rho0
    return 113;
  case 210:
    //pi_diffr+ -- change to pi+
    return 211;
  case 220:
    //omega_di0 -- change to omega0
    return 223;
  case 330:
    //phi_diff0 -- return phi0
    return 333;
  case 440:
    //J/psi_di0 -- return J/psi
    return 443;
  case 2110:
    //n_diffr -- return neutron
    return 2112;
  case 2210:
    //p_diffr+ -- return proton
    return 2212;
  }
  //non diffractive state -- return code unchanged
  return pdgcode;
}

AliGenMC& AliGenMC::operator=(const  AliGenMC& rhs)
{
// Assignment operator
    return *this;
}

<|endoftext|>


<commit_before>// =-=-=-=-=-=-=-
#include "irods_auth_factory.hpp"
#include "irods_native_auth_object.hpp"
#include "irods_pam_auth_object.hpp"
#include "irods_osauth_auth_object.hpp"
#include "irods_gsi_object.hpp"
#include "irods_krb_object.hpp"
#include <boost/algorithm/string.hpp>

namespace irods {
/// =-=-=-=-=-=-=-
/// @brief super basic free factory function to create an auth object
///        given the requested authentication scheme
    error auth_factory(
        const std::string& _scheme,
        rError_t*          _r_error,
        auth_object_ptr&   _ptr ) {
        // ensure scheme is lower case for comparison
        std::string scheme = boost::algorithm::to_lower_copy( _scheme );

        if ( scheme.empty() || AUTH_NATIVE_SCHEME == scheme ) {
            _ptr.reset( new native_auth_object( _r_error ) );
        }
        else if ( AUTH_PAM_SCHEME == scheme ) {
            _ptr.reset( new pam_auth_object( _r_error ) );
        }
        else if ( AUTH_OSAUTH_SCHEME == scheme ) {
            _ptr.reset( new osauth_auth_object( _r_error ) );
        }
        else if ( AUTH_GSI_SCHEME == scheme ) {
            _ptr.reset( new gsi_auth_object( _r_error ) );
        }
        else if ( AUTH_KRB_SCHEME == scheme ) {
            _ptr.reset( new krb_auth_object( _r_error ) );
        }
        else {
            std::string msg( "auth scheme not supported [" );
            msg += scheme + "]";
            return ERROR( SYS_INVALID_INPUT_PARAM, msg );
        }

        return SUCCESS();

    } // auth_factory

}; // namespace irods

<commit_msg>gsseap auth object<commit_after>// =-=-=-=-=-=-=-
#include "irods_auth_factory.hpp"
#include "irods_native_auth_object.hpp"
#include "irods_pam_auth_object.hpp"
#include "irods_osauth_auth_object.hpp"
#include "irods_gsi_object.hpp"
#include "irods_krb_object.hpp"
#include "irods_gsseap_object.hpp"
#include <boost/algorithm/string.hpp>

namespace irods {
/// =-=-=-=-=-=-=-
/// @brief super basic free factory function to create an auth object
///        given the requested authentication scheme
    error auth_factory(
        const std::string& _scheme,
        rError_t*          _r_error,
        auth_object_ptr&   _ptr ) {
        // ensure scheme is lower case for comparison
        std::string scheme = boost::algorithm::to_lower_copy( _scheme );

        if ( scheme.empty() || AUTH_NATIVE_SCHEME == scheme ) {
            _ptr.reset( new native_auth_object( _r_error ) );
        }
        else if ( AUTH_PAM_SCHEME == scheme ) {
            _ptr.reset( new pam_auth_object( _r_error ) );
        }
        else if ( AUTH_OSAUTH_SCHEME == scheme ) {
            _ptr.reset( new osauth_auth_object( _r_error ) );
        }
        else if ( AUTH_GSI_SCHEME == scheme ) {
            _ptr.reset( new gsi_auth_object( _r_error ) );
        }
        else if ( AUTH_KRB_SCHEME == scheme ) {
            _ptr.reset( new krb_auth_object( _r_error ) );
        }
	else if ( AUTH_GSSEAP_SCHEME == scheme ) {
	    _ptr.reset( new gsseap_auth_object( _r_error ) );
	}
        else {
            std::string msg( "auth scheme not supported [" );
            msg += scheme + "]";
            return ERROR( SYS_INVALID_INPUT_PARAM, msg );
        }

        return SUCCESS();

    } // auth_factory

}; // namespace irods

<|endoftext|>


<commit_before>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "jnc_rt_ExceptionMgr.h"
#include "jnc_rt_Runtime.h"
#include "jnc_Runtime.h"

// #define _JNC_NO_EH 1

namespace jnc {
namespace rt {

//..............................................................................

#if (_JNC_OS_POSIX)

void
ExceptionMgr::install()
{
	int result;
	sigset_t signalMask;
	sigemptyset(&signalMask);
	sigaddset(&signalMask, SIGSEGV);
	sigaddset(&signalMask, SIGBUS);
	sigaddset(&signalMask, SIGFPE);
	sigaddset(&signalMask, SIGILL);

	struct sigaction sigAction = { 0 };
	sigAction.sa_flags = SA_SIGINFO;
	sigAction.sa_mask = signalMask;

	sigAction.sa_sigaction = signalHandler;
	result = sigaction(SIGSEGV, &sigAction, &m_prevSigActionTable[SIGSEGV]);
	ASSERT(result == 0);

	result = sigaction(SIGBUS, &sigAction, &m_prevSigActionTable[SIGBUS]);
	ASSERT(result == 0);

	result = sigaction(SIGFPE, &sigAction, &m_prevSigActionTable[SIGFPE]);
	ASSERT(result == 0);

	result = sigaction(SIGILL, &sigAction, &m_prevSigActionTable[SIGILL]);
	ASSERT(result == 0);

	sigAction.sa_sigaction = signalHandler_SIGUSR;
	result = sigaction(SIGUSR1, &sigAction, &m_prevSigActionTable[SIGUSR1]);
	ASSERT(result == 0);
}

void
ExceptionMgr::signalHandler(
	int signal,
	siginfo_t* signalInfo,
	void* context
	)
{
	enum
	{
#if (_JNC_OS_DARWIN)
		GcGuardPageHitSignal = SIGBUS
#else
		GcGuardPageHitSignal = SIGSEGV
#endif
	};

	// while POSIX does not require pthread_getspecific to be async-signal-safe, in practice it is

	Tls* tls = getCurrentThreadTls();
	if (!tls)
	{
		sl::getSimpleSingleton<ExceptionMgr> ()->invokePrevSignalHandler(signal, signalInfo, context);
		return;
	}

	if (signal == GcGuardPageHitSignal)
	{
		GcHeap* gcHeap = tls->m_runtime->getGcHeap();
		if (signalInfo->si_addr == gcHeap->getGuardPage())
		{
			gcHeap->handleGuardPageHit(&tls->m_gcMutatorThread);
			return;
		}
	}

#if (_JNC_NO_EH)
	sl::getSimpleSingleton<ExceptionMgr> ()->invokePrevSignalHandler(signal, signalInfo, context);
#else
	TlsVariableTable* tlsVariableTable = (TlsVariableTable*)(tls + 1);
	if (!tlsVariableTable->m_sjljFrame)
	{
		sl::getSimpleSingleton<ExceptionMgr> ()->invokePrevSignalHandler(signal, signalInfo, context);
	}
	else
	{
		const ucontext_t* ucontext = (ucontext_t *)context;
#	if (_JNC_CPU_AMD64)
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_codeAddress = ucontext->uc_mcontext.gregs[REG_RIP];
#	elif (_JNC_CPU_X86)
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_codeAddress = ucontext->uc_mcontext.gregs[REG_EIP];
#	elif (_JNC_CPU_ARM32)
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_codeAddress = ucontext->uc_mcontext.arm_pc;
#	else
#		error unsupported CPU architecture
#	endif
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_signal = signal;
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_code = signalInfo->si_code;
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_faultAddress = (uintptr_t)signalInfo->si_addr;
		jnc_longJmp(tlsVariableTable->m_sjljFrame->m_jmpBuf, -1);
		ASSERT(false);
	}
#endif
}

void
ExceptionMgr::signalHandler_SIGUSR(
	int signal,
	siginfo_t* signalInfo,
	void* context
	)
{
	// while POSIX does not require pthread_getspecific to be async-signal-safe, in practice it is

	Tls* tls = getCurrentThreadTls();
	if (!tls)
		sl::getSimpleSingleton<ExceptionMgr> ()->invokePrevSignalHandler(signal, signalInfo, context);

	// do nothing (we gc-handshake manually). but we still need a handler
}

void
ExceptionMgr::invokePrevSignalHandler(
	int signal,
	siginfo_t* signalInfo,
	void* context
	)
{
	const struct sigaction* prevSigAction = &m_prevSigActionTable[signal];

	if (prevSigAction->sa_handler == SIG_IGN)
	{
		return;
	}
	else if (prevSigAction->sa_handler == SIG_DFL)
	{
		// no other choice but to restore and re-raise
		sigaction(signal, &m_prevSigActionTable[signal], NULL);
		raise(signal);
	}
	else if (!(prevSigAction->sa_flags & SA_SIGINFO))
	{
		prevSigAction->sa_handler(signal);
	}
	else if (prevSigAction->sa_sigaction)
	{
		prevSigAction->sa_sigaction(signal, signalInfo, context);
	}
}

#elif (_AXL_OS_WIN)

void
ExceptionMgr::install()
{
	::AddVectoredExceptionHandler(true, vectoredExceptionHandler);
}

LONG
WINAPI
ExceptionMgr::vectoredExceptionHandler(EXCEPTION_POINTERS* exceptionPointers)
{
	LONG status = exceptionPointers->ExceptionRecord->ExceptionCode;
	if (status >= 0) // we only care about NT error conditions
		return EXCEPTION_CONTINUE_SEARCH;

	Tls* tls = getCurrentThreadTls();
	if (!tls)
		return EXCEPTION_CONTINUE_SEARCH;

	GcHeap* gcHeap = tls->m_runtime->getGcHeap();

	if (status == EXCEPTION_ACCESS_VIOLATION &&
		exceptionPointers->ExceptionRecord->ExceptionInformation[1] == (uintptr_t)gcHeap->getGuardPage())
	{
		gcHeap->handleGuardPageHit(&tls->m_gcMutatorThread);
		return EXCEPTION_CONTINUE_EXECUTION;
	}

#if (_JNC_NO_EH)
	return EXCEPTION_CONTINUE_SEARCH;
#else
	TlsVariableTable* tlsVariableTable = (TlsVariableTable*)(tls + 1);
	if (tlsVariableTable->m_sjljFrame)
	{
		sys::setWinExceptionError(
			status,
			(uintptr_t)exceptionPointers->ExceptionRecord->ExceptionAddress,
			(const uintptr_t*)exceptionPointers->ExceptionRecord->ExceptionInformation,
			exceptionPointers->ExceptionRecord->NumberParameters
			);

		jnc_longJmp(tlsVariableTable->m_sjljFrame->m_jmpBuf, -1);
		ASSERT(false);
	}

	return EXCEPTION_CONTINUE_SEARCH;
#endif
}

#endif

//..............................................................................

} // namespace rt
} // namespace jnc
<commit_msg>[jnc_rt] fix: uc_mcontext access fix on darwin-amd64<commit_after>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "jnc_rt_ExceptionMgr.h"
#include "jnc_rt_Runtime.h"
#include "jnc_Runtime.h"

// #define _JNC_NO_EH 1

namespace jnc {
namespace rt {

//..............................................................................

#if (_JNC_OS_POSIX)

void
ExceptionMgr::install()
{
	int result;
	sigset_t signalMask;
	sigemptyset(&signalMask);
	sigaddset(&signalMask, SIGSEGV);
	sigaddset(&signalMask, SIGBUS);
	sigaddset(&signalMask, SIGFPE);
	sigaddset(&signalMask, SIGILL);

	struct sigaction sigAction = { 0 };
	sigAction.sa_flags = SA_SIGINFO;
	sigAction.sa_mask = signalMask;

	sigAction.sa_sigaction = signalHandler;
	result = sigaction(SIGSEGV, &sigAction, &m_prevSigActionTable[SIGSEGV]);
	ASSERT(result == 0);

	result = sigaction(SIGBUS, &sigAction, &m_prevSigActionTable[SIGBUS]);
	ASSERT(result == 0);

	result = sigaction(SIGFPE, &sigAction, &m_prevSigActionTable[SIGFPE]);
	ASSERT(result == 0);

	result = sigaction(SIGILL, &sigAction, &m_prevSigActionTable[SIGILL]);
	ASSERT(result == 0);

	sigAction.sa_sigaction = signalHandler_SIGUSR;
	result = sigaction(SIGUSR1, &sigAction, &m_prevSigActionTable[SIGUSR1]);
	ASSERT(result == 0);
}

void
ExceptionMgr::signalHandler(
	int signal,
	siginfo_t* signalInfo,
	void* context
	)
{
	enum
	{
#if (_JNC_OS_DARWIN)
		GcGuardPageHitSignal = SIGBUS
#else
		GcGuardPageHitSignal = SIGSEGV
#endif
	};

	// while POSIX does not require pthread_getspecific to be async-signal-safe, in practice it is

	Tls* tls = getCurrentThreadTls();
	if (!tls)
	{
		sl::getSimpleSingleton<ExceptionMgr> ()->invokePrevSignalHandler(signal, signalInfo, context);
		return;
	}

	if (signal == GcGuardPageHitSignal)
	{
		GcHeap* gcHeap = tls->m_runtime->getGcHeap();
		if (signalInfo->si_addr == gcHeap->getGuardPage())
		{
			gcHeap->handleGuardPageHit(&tls->m_gcMutatorThread);
			return;
		}
	}

#if (_JNC_NO_EH)
	sl::getSimpleSingleton<ExceptionMgr> ()->invokePrevSignalHandler(signal, signalInfo, context);
#else
	TlsVariableTable* tlsVariableTable = (TlsVariableTable*)(tls + 1);
	if (!tlsVariableTable->m_sjljFrame)
	{
		sl::getSimpleSingleton<ExceptionMgr> ()->invokePrevSignalHandler(signal, signalInfo, context);
	}
	else
	{
		const ucontext_t* ucontext = (ucontext_t *)context;
#	if (_JNC_OS_DARWIN)
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_codeAddress = ucontext->uc_mcontext->__ss.__rip;
#	elif (_JNC_CPU_AMD64)
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_codeAddress = ucontext->uc_mcontext.gregs[REG_RIP];
#	elif (_JNC_CPU_X86)
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_codeAddress = ucontext->uc_mcontext.gregs[REG_EIP];
#	elif (_JNC_CPU_ARM32)
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_codeAddress = ucontext->uc_mcontext.arm_pc;
#	else
#		error unsupported CPU architecture
#	endif
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_signal = signal;
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_code = signalInfo->si_code;
		tlsVariableTable->m_sjljFrame->m_signalInfo.m_faultAddress = (uintptr_t)signalInfo->si_addr;
		jnc_longJmp(tlsVariableTable->m_sjljFrame->m_jmpBuf, -1);
		ASSERT(false);
	}
#endif
}

void
ExceptionMgr::signalHandler_SIGUSR(
	int signal,
	siginfo_t* signalInfo,
	void* context
	)
{
	// while POSIX does not require pthread_getspecific to be async-signal-safe, in practice it is

	Tls* tls = getCurrentThreadTls();
	if (!tls)
		sl::getSimpleSingleton<ExceptionMgr> ()->invokePrevSignalHandler(signal, signalInfo, context);

	// do nothing (we gc-handshake manually). but we still need a handler
}

void
ExceptionMgr::invokePrevSignalHandler(
	int signal,
	siginfo_t* signalInfo,
	void* context
	)
{
	const struct sigaction* prevSigAction = &m_prevSigActionTable[signal];

	if (prevSigAction->sa_handler == SIG_IGN)
	{
		return;
	}
	else if (prevSigAction->sa_handler == SIG_DFL)
	{
		// no other choice but to restore and re-raise
		sigaction(signal, &m_prevSigActionTable[signal], NULL);
		raise(signal);
	}
	else if (!(prevSigAction->sa_flags & SA_SIGINFO))
	{
		prevSigAction->sa_handler(signal);
	}
	else if (prevSigAction->sa_sigaction)
	{
		prevSigAction->sa_sigaction(signal, signalInfo, context);
	}
}

#elif (_AXL_OS_WIN)

void
ExceptionMgr::install()
{
	::AddVectoredExceptionHandler(true, vectoredExceptionHandler);
}

LONG
WINAPI
ExceptionMgr::vectoredExceptionHandler(EXCEPTION_POINTERS* exceptionPointers)
{
	LONG status = exceptionPointers->ExceptionRecord->ExceptionCode;
	if (status >= 0) // we only care about NT error conditions
		return EXCEPTION_CONTINUE_SEARCH;

	Tls* tls = getCurrentThreadTls();
	if (!tls)
		return EXCEPTION_CONTINUE_SEARCH;

	GcHeap* gcHeap = tls->m_runtime->getGcHeap();

	if (status == EXCEPTION_ACCESS_VIOLATION &&
		exceptionPointers->ExceptionRecord->ExceptionInformation[1] == (uintptr_t)gcHeap->getGuardPage())
	{
		gcHeap->handleGuardPageHit(&tls->m_gcMutatorThread);
		return EXCEPTION_CONTINUE_EXECUTION;
	}

#if (_JNC_NO_EH)
	return EXCEPTION_CONTINUE_SEARCH;
#else
	TlsVariableTable* tlsVariableTable = (TlsVariableTable*)(tls + 1);
	if (tlsVariableTable->m_sjljFrame)
	{
		sys::setWinExceptionError(
			status,
			(uintptr_t)exceptionPointers->ExceptionRecord->ExceptionAddress,
			(const uintptr_t*)exceptionPointers->ExceptionRecord->ExceptionInformation,
			exceptionPointers->ExceptionRecord->NumberParameters
			);

		jnc_longJmp(tlsVariableTable->m_sjljFrame->m_jmpBuf, -1);
		ASSERT(false);
	}

	return EXCEPTION_CONTINUE_SEARCH;
#endif
}

#endif

//..............................................................................

} // namespace rt
} // namespace jnc
<|endoftext|>


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

#include "PrimeNumberFinder.h"
#include "PrimeSieve.h"
#include "SieveOfEratosthenes.h"
#include "config.h"
#include "bithacks.h"

#include <stdint.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <sstream>

#if defined(_OPENMP)
  #include <omp.h>
#endif

namespace soe {

/// Bit patterns corresponding to prime k-tuplets
/// within bytes of the sieve array.
const uint32_t PrimeNumberFinder::kTupletBitmasks_[6][5] =
{
  { 0x06, 0x18, 0xc0, END },       // Twin primes
  { 0x07, 0x0e, 0x1c, 0x38, END }, // Prime triplets
  { 0x1e, END },                   // Prime quadruplets
  { 0x1f, 0x3e, END },             // Prime quintuplets
  { 0x3f, END },                   // Prime sextuplets
  { 0xfe, END }                    // Prime septuplets
};

PrimeNumberFinder::PrimeNumberFinder(PrimeSieve& ps) :
  SieveOfEratosthenes(
      std::max<uint64_t>(7, ps.getStart()),
      ps.getStop(),
      ps.getPreSieveLimit(),
      ps.getSieveSize()),
  ps_(ps),
  kTupletByteCounts_(NULL)
{
  static_assert(PrimeSieve::COUNTS_SIZE == 7, "PrimeSieve::COUNTS_SIZE == 7");
  if (ps_.testFlags(ps_.COUNT_KTUPLETS))
    this->initLookupTables();
}

PrimeNumberFinder::~PrimeNumberFinder() {
  if (kTupletByteCounts_ != NULL) {
    for (int i = 0; i < 6; i++)
      delete[] kTupletByteCounts_[i];
    delete[] kTupletByteCounts_;
  }
}

/**
 * Check if PrimeNumberFinder requires a PrimeNumberGenerator
 * object to generate its sieving primes.
 */
bool PrimeNumberFinder::needGenerator() const {
  return (this->getSquareRoot() > this->getPreSieveLimit());
}

/**
 * Initialize the lookup tables needed to count prime k-tuplets
 * (twin primes, prime triplets, ...) per byte.
 */
void PrimeNumberFinder::initLookupTables() {
  kTupletByteCounts_ = new uint32_t*[6];
  for (uint32_t i = 0; i < 6; i++) {
    kTupletByteCounts_[i] = NULL;
    if (ps_.isFlag(ps_.COUNT_TWINS << i)) {
      kTupletByteCounts_[i] = new uint32_t[256];
      for (uint32_t j = 0; j < 256; j++) {
        uint32_t bitmaskCount = 0;
        for (const uint32_t* b = kTupletBitmasks_[i]; *b <= j; b++) {
          if ((j & *b) == *b)
            bitmaskCount++;
        }
        kTupletByteCounts_[i][j] = bitmaskCount;
      }
    }
  }
}

/**
 * Generate/count the primes and prime k-tuplets within the current
 * segment i.e. [segmentLow_+7, segmentHigh_].
 */
void PrimeNumberFinder::analyseSieve(const uint8_t* sieve, uint32_t sieveSize) {
  if (ps_.testFlags(ps_.COUNT_FLAGS))
    this->count(sieve, sieveSize);
  if (ps_.testFlags(ps_.GENERATE_FLAGS))
    this->generate(sieve, sieveSize);
  if (ps_.isFlag(ps_.CALCULATE_STATUS))
    ps_()->calcStatus(sieveSize * NUMBERS_PER_BYTE);
}

/**
 * Count the primes and prime k-tuplets within
 * the current segment.
 */
void PrimeNumberFinder::count(const uint8_t* sieve, uint32_t sieveSize) {
  // count prime numbers (1 bits within the sieve array)
  if (ps_.isFlag(ps_.COUNT_PRIMES)) {
    const uint64_t* sieve64 = reinterpret_cast<const uint64_t*>(sieve);
    uint32_t sieveSize64 = sieveSize / 8;
    uint32_t bytesLeft = sieveSize % 8;
    // see bithacks.h
    uint32_t primeCount = popcount_lauradoux(sieve64, sieveSize64);
    if (bytesLeft > 0)
      primeCount += popcount_kernighan(&sieve[sieveSize - bytesLeft], bytesLeft);
    // add up to total prime count
    ps_.counts_[0] += primeCount;
  }
  // count prime k-tuplets (i=0 twins, i=1 triplets, ...)
  // using lookup tables
  for (uint32_t i = 0; i < 6; i++) {
    if (ps_.isFlag(ps_.COUNT_TWINS << i)) {
      uint32_t kCount = 0;
      for (uint32_t j = 0; j < sieveSize; j++)
        kCount += kTupletByteCounts_[i][sieve[j]];
      ps_.counts_[i+1] += kCount;
    }
  }
}

/**
 * Generate the primes or prime k-tuplets (twin primes, prime
 * triplets, ...) within the current segment.
 */
void PrimeNumberFinder::generate(const uint8_t* sieve, uint32_t sieveSize) {
  if (ps_.testFlags(ps_.PRINT_KTUPLETS)) {
    const uint64_t segmentLow = this->getSegmentLow();
    // i = 0 twins, i = 1 triplets, ...
    uint32_t i = 0;
    for (; !ps_.isFlag(ps_.PRINT_TWINS << i); i++)
      ;
    // print prime k-tuplets to std::cout
    for (uint32_t j = 0; j < sieveSize; j++) {
      for (const uint32_t* bitmask = kTupletBitmasks_[i]; *bitmask <= sieve[j]; bitmask++) {
        if ((sieve[j] & *bitmask) == *bitmask) {
          std::ostringstream kTuplet;
          kTuplet << "(";
          uint32_t bits = *bitmask;
          uint64_t offset = segmentLow + j * NUMBERS_PER_BYTE;
          for (; bits & (bits - 1); bits &= bits - 1)
            kTuplet << offset + this->getFirstSetBitValue(bits) << ", ";
          kTuplet << offset + this->getFirstSetBitValue(bits) << ")\n";
          std::cout << kTuplet.str();
        }
      }
    }
  }
  else
#if defined(_OPENMP)
  #pragma omp critical (generate)
#endif
  {
    // GENERATE_PRIMES() is defined in SieveOfEratosthenes.h
         if (ps_.isFlag(ps_.CALLBACK32_PRIMES))     GENERATE_PRIMES(ps_.callback32_,      uint32_t)
    else if (ps_.isFlag(ps_.CALLBACK32_OOP_PRIMES)) GENERATE_PRIMES(this->callback32_OOP, uint32_t)
    else if (ps_.isFlag(ps_.CALLBACK64_PRIMES))     GENERATE_PRIMES(ps_.callback64_,      uint64_t)
    else if (ps_.isFlag(ps_.CALLBACK64_OOP_PRIMES)) GENERATE_PRIMES(this->callback64_OOP, uint64_t)
    else if (ps_.isFlag(ps_.PRINT_PRIMES))          GENERATE_PRIMES(this->print,          uint64_t)
  }
}

void PrimeNumberFinder::callback32_OOP(uint32_t prime) const {
  ps_.callback32_OOP_(prime, ps_.cbObj_);
}

void PrimeNumberFinder::callback64_OOP(uint64_t prime) const {
  ps_.callback64_OOP_(prime, ps_.cbObj_);
}

void PrimeNumberFinder::print(uint64_t prime) const {
  std::cout << prime << '\n';
}

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

#include "PrimeNumberFinder.h"
#include "PrimeSieve.h"
#include "SieveOfEratosthenes.h"
#include "config.h"
#include "bithacks.h"

#include <stdint.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <sstream>

#if defined(_OPENMP)
  #include <omp.h>
#endif

namespace soe {

/// Bit patterns corresponding to prime k-tuplets
/// within bytes of the sieve array.
const uint32_t PrimeNumberFinder::kTupletBitmasks_[6][5] =
{
  { 0x06, 0x18, 0xc0, END },       // Twin primes
  { 0x07, 0x0e, 0x1c, 0x38, END }, // Prime triplets
  { 0x1e, END },                   // Prime quadruplets
  { 0x1f, 0x3e, END },             // Prime quintuplets
  { 0x3f, END },                   // Prime sextuplets
  { 0xfe, END }                    // Prime septuplets
};

PrimeNumberFinder::PrimeNumberFinder(PrimeSieve& ps) :
  SieveOfEratosthenes(
      std::max<uint64_t>(7, ps.getStart()),
      ps.getStop(),
      ps.getPreSieveLimit(),
      ps.getSieveSize()),
  ps_(ps),
  kTupletByteCounts_(NULL)
{
  static_assert(PrimeSieve::COUNTS_SIZE == 7, "PrimeSieve::COUNTS_SIZE == 7");
  if (ps_.testFlags(ps_.COUNT_KTUPLETS))
    initLookupTables();
}

PrimeNumberFinder::~PrimeNumberFinder() {
  if (kTupletByteCounts_ != NULL) {
    for (int i = 0; i < 6; i++)
      delete[] kTupletByteCounts_[i];
    delete[] kTupletByteCounts_;
  }
}

/**
 * Check if PrimeNumberFinder requires a PrimeNumberGenerator
 * object to generate its sieving primes.
 */
bool PrimeNumberFinder::needGenerator() const {
  return getPreSieveLimit() < getSquareRoot();
}

/**
 * Initialize the lookup tables needed to count prime k-tuplets
 * (twin primes, prime triplets, ...) per byte.
 */
void PrimeNumberFinder::initLookupTables() {
  kTupletByteCounts_ = new uint32_t*[6];
  for (uint32_t i = 0; i < 6; i++) {
    kTupletByteCounts_[i] = NULL;
    if (ps_.isFlag(ps_.COUNT_TWINS << i)) {
      kTupletByteCounts_[i] = new uint32_t[256];
      for (uint32_t j = 0; j < 256; j++) {
        uint32_t bitmaskCount = 0;
        for (const uint32_t* b = kTupletBitmasks_[i]; *b <= j; b++) {
          if ((j & *b) == *b)
            bitmaskCount++;
        }
        kTupletByteCounts_[i][j] = bitmaskCount;
      }
    }
  }
}

/**
 * Generate/count the primes and prime k-tuplets within the current
 * segment i.e. [segmentLow_+7, segmentHigh_].
 */
void PrimeNumberFinder::analyseSieve(const uint8_t* sieve, uint32_t sieveSize) {
  if (ps_.testFlags(ps_.COUNT_FLAGS))
    count(sieve, sieveSize);
  if (ps_.testFlags(ps_.GENERATE_FLAGS))
    generate(sieve, sieveSize);
  if (ps_.isFlag(ps_.CALCULATE_STATUS))
    ps_()->calcStatus(sieveSize * NUMBERS_PER_BYTE);
}

/**
 * Count the primes and prime k-tuplets within
 * the current segment.
 */
void PrimeNumberFinder::count(const uint8_t* sieve, uint32_t sieveSize) {
  // count prime numbers (1 bits within the sieve array)
  if (ps_.isFlag(ps_.COUNT_PRIMES)) {
    const uint64_t* sieve64 = reinterpret_cast<const uint64_t*>(sieve);
    uint32_t sieveSize64 = sieveSize / 8;
    uint32_t bytesLeft = sieveSize % 8;
    // see bithacks.h
    uint32_t primeCount = popcount_lauradoux(sieve64, sieveSize64);
    if (bytesLeft > 0)
      primeCount += popcount_kernighan(&sieve[sieveSize - bytesLeft], bytesLeft);
    // add up to total prime count
    ps_.counts_[0] += primeCount;
  }
  // count prime k-tuplets (i=0 twins, i=1 triplets, ...)
  // using lookup tables
  for (uint32_t i = 0; i < 6; i++) {
    if (ps_.isFlag(ps_.COUNT_TWINS << i)) {
      uint32_t kCount = 0;
      for (uint32_t j = 0; j < sieveSize; j++)
        kCount += kTupletByteCounts_[i][sieve[j]];
      ps_.counts_[i+1] += kCount;
    }
  }
}

/**
 * Generate the primes or prime k-tuplets (twin primes, prime
 * triplets, ...) within the current segment.
 */
void PrimeNumberFinder::generate(const uint8_t* sieve, uint32_t sieveSize) {
  if (ps_.testFlags(ps_.PRINT_KTUPLETS)) {
    const uint64_t segmentLow = getSegmentLow();
    // i = 0 twins, i = 1 triplets, ...
    uint32_t i = 0;
    for (; !ps_.isFlag(ps_.PRINT_TWINS << i); i++)
      ;
    // print prime k-tuplets to std::cout
    for (uint32_t j = 0; j < sieveSize; j++) {
      for (const uint32_t* bitmask = kTupletBitmasks_[i]; *bitmask <= sieve[j]; bitmask++) {
        if ((sieve[j] & *bitmask) == *bitmask) {
          std::ostringstream kTuplet;
          kTuplet << "(";
          uint32_t bits = *bitmask;
          uint64_t offset = segmentLow + j * NUMBERS_PER_BYTE;
          for (; bits & (bits - 1); bits &= bits - 1)
            kTuplet << offset + getFirstSetBitValue(bits) << ", ";
          kTuplet << offset + getFirstSetBitValue(bits) << ")\n";
          std::cout << kTuplet.str();
        }
      }
    }
  }
  else
#if defined(_OPENMP)
  #pragma omp critical (generate)
#endif
  {
    // GENERATE_PRIMES() is defined in SieveOfEratosthenes.h
         if (ps_.isFlag(ps_.CALLBACK32_PRIMES))     GENERATE_PRIMES(ps_.callback32_, uint32_t)
    else if (ps_.isFlag(ps_.CALLBACK32_OOP_PRIMES)) GENERATE_PRIMES(callback32_OOP,  uint32_t)
    else if (ps_.isFlag(ps_.CALLBACK64_PRIMES))     GENERATE_PRIMES(ps_.callback64_, uint64_t)
    else if (ps_.isFlag(ps_.CALLBACK64_OOP_PRIMES)) GENERATE_PRIMES(callback64_OOP,  uint64_t)
    else if (ps_.isFlag(ps_.PRINT_PRIMES))          GENERATE_PRIMES(print,           uint64_t)
  }
}

void PrimeNumberFinder::callback32_OOP(uint32_t prime) const {
  ps_.callback32_OOP_(prime, ps_.cbObj_);
}

void PrimeNumberFinder::callback64_OOP(uint64_t prime) const {
  ps_.callback64_OOP_(prime, ps_.cbObj_);
}

void PrimeNumberFinder::print(uint64_t prime) const {
  std::cout << prime << '\n';
}

} // namespace soe
<|endoftext|>