<commit_before>//===- GsymCreator.cpp ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//===----------------------------------------------------------------------===//

#include "llvm/DebugInfo/GSYM/GsymCreator.h"
#include "llvm/DebugInfo/GSYM/FileWriter.h"
#include "llvm/DebugInfo/GSYM/Header.h"
#include "llvm/DebugInfo/GSYM/LineTable.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/raw_ostream.h"

#include <algorithm>
#include <cassert>
#include <strings.h>

using namespace llvm;
using namespace gsym;

GsymCreator::GsymCreator() : StrTab(StringTableBuilder::ELF) {
  insertFile(StringRef());
}

uint32_t GsymCreator::insertFile(StringRef Path,
                                 llvm::sys::path::Style Style) {
  llvm::StringRef directory = llvm::sys::path::parent_path(Path, Style);
  llvm::StringRef filename = llvm::sys::path::filename(Path, Style);
  FileEntry FE(insertString(directory), insertString(filename));

  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  const auto NextIndex = Files.size();
  // Find FE in hash map and insert if not present.
  auto R = FileEntryToIndex.insert(std::make_pair(FE, NextIndex));
  if (R.second)
    Files.emplace_back(FE);
  return R.first->second;
}

llvm::Error GsymCreator::save(StringRef Path,
                              llvm::support::endianness ByteOrder) const {
  std::error_code EC;
  raw_fd_ostream OutStrm(Path, EC);
  if (EC)
    return llvm::errorCodeToError(EC);
  FileWriter O(OutStrm, ByteOrder);
  return encode(O);
}

llvm::Error GsymCreator::encode(FileWriter &O) const {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  if (Funcs.empty())
    return createStringError(std::errc::invalid_argument,
                             "no functions to encode");
  if (!Finalized)
    return createStringError(std::errc::invalid_argument,
                             "GsymCreator wasn't finalized prior to encoding");

  if (Funcs.size() > UINT32_MAX)
    return createStringError(std::errc::invalid_argument,
                             "too many FunctionInfos");
  const uint64_t MinAddr = Funcs.front().startAddress();
  const uint64_t MaxAddr = Funcs.back().startAddress();
  const uint64_t AddrDelta = MaxAddr - MinAddr;
  Header Hdr;
  Hdr.Magic = GSYM_MAGIC;
  Hdr.Version = GSYM_VERSION;
  Hdr.AddrOffSize = 0;
  Hdr.UUIDSize = static_cast<uint8_t>(UUID.size());
  Hdr.BaseAddress = MinAddr;
  Hdr.NumAddresses = static_cast<uint32_t>(Funcs.size());
  Hdr.StrtabOffset = 0; // We will fix this up later.
  Hdr.StrtabOffset = 0; // We will fix this up later.
  bzero(Hdr.UUID, sizeof(Hdr.UUID));
  if (UUID.size() > sizeof(Hdr.UUID))
    return createStringError(std::errc::invalid_argument,
                             "invalid UUID size %u", (uint32_t)UUID.size());
  // Set the address offset size correctly in the GSYM header.
  if (AddrDelta <= UINT8_MAX)
    Hdr.AddrOffSize = 1;
  else if (AddrDelta <= UINT16_MAX)
    Hdr.AddrOffSize = 2;
  else if (AddrDelta <= UINT32_MAX)
    Hdr.AddrOffSize = 4;
  else
    Hdr.AddrOffSize = 8;
  // Copy the UUID value if we have one.
  if (UUID.size() > 0)
    memcpy(Hdr.UUID, UUID.data(), UUID.size());
  // Write out the header.
  llvm::Error Err = Hdr.encode(O);
  if (Err)
    return Err;

  // Write out the address offsets.
  O.alignTo(Hdr.AddrOffSize);
  for (const auto &FuncInfo : Funcs) {
    uint64_t AddrOffset = FuncInfo.startAddress() - Hdr.BaseAddress;
    switch(Hdr.AddrOffSize) {
      case 1: O.writeU8(static_cast<uint8_t>(AddrOffset)); break;
      case 2: O.writeU16(static_cast<uint16_t>(AddrOffset)); break;
      case 4: O.writeU32(static_cast<uint32_t>(AddrOffset)); break;
      case 8: O.writeU64(AddrOffset); break;
    }
  }

  // Write out all zeros for the AddrInfoOffsets.
  O.alignTo(4);
  const off_t AddrInfoOffsetsOffset = O.tell();
  for (size_t i = 0, n = Funcs.size(); i < n; ++i)
    O.writeU32(0);

  // Write out the file table
  O.alignTo(4);
  assert(!Files.empty());
  assert(Files[0].Dir == 0);
  assert(Files[0].Base == 0);
  size_t NumFiles = Files.size();
  if (NumFiles > UINT32_MAX)
    return createStringError(std::errc::invalid_argument,
                             "too many files");
  O.writeU32(static_cast<uint32_t>(NumFiles));
  for (auto File: Files) {
      O.writeU32(File.Dir);
      O.writeU32(File.Base);
  }

  // Write out the sting table.
  const off_t StrtabOffset = O.tell();
  StrTab.write(O.get_stream());
  const off_t StrtabSize = O.tell() - StrtabOffset;
  std::vector<uint32_t> AddrInfoOffsets;

  // Write out the address infos for each function info.
  for (const auto &FuncInfo : Funcs) {
    if (Expected<uint64_t> OffsetOrErr = FuncInfo.encode(O))
        AddrInfoOffsets.push_back(OffsetOrErr.get());
    else
        return OffsetOrErr.takeError();
  }
  // Fixup the string table offset and size in the header
  O.fixup32((uint32_t)StrtabOffset, offsetof(Header, StrtabOffset));
  O.fixup32((uint32_t)StrtabSize, offsetof(Header, StrtabSize));

  // Fixup all address info offsets
  uint64_t Offset = 0;
  for (auto AddrInfoOffset: AddrInfoOffsets) {
    O.fixup32(AddrInfoOffset, AddrInfoOffsetsOffset + Offset);
    Offset += 4;
  }
  return ErrorSuccess();
}

llvm::Error GsymCreator::finalize(llvm::raw_ostream &OS) {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  if (Finalized)
    return createStringError(std::errc::invalid_argument,
                             "already finalized");
  Finalized = true;

  // Sort function infos so we can emit sorted functions.
  llvm::sort(Funcs.begin(), Funcs.end());

  // Don't let the string table indexes change by finalizing in order.
  StrTab.finalizeInOrder();

  // Remove duplicates function infos that have both entries from debug info
  // (DWARF or Breakpad) and entries from the SymbolTable.
  //
  // Also handle overlapping function. Usually there shouldn't be any, but they
  // can and do happen in some rare cases.
  //
  // (a)          (b)         (c)
  //     ^  ^       ^            ^
  //     |X |Y      |X ^         |X
  //     |  |       |  |Y        |  ^
  //     |  |       |  v         v  |Y
  //     v  v       v               v
  //
  // In (a) and (b), Y is ignored and X will be reported for the full range.
  // In (c), both functions will be included in the result and lookups for an
  // address in the intersection will return Y because of binary search.
  //
  // Note that in case of (b), we cannot include Y in the result because then
  // we wouldn't find any function for range (end of Y, end of X)
  // with binary search
  auto NumBefore = Funcs.size();
  auto Curr = Funcs.begin();
  auto Prev = Funcs.end();
  while (Curr != Funcs.end()) {
    // Can't check for overlaps or same address ranges if we don't have a
    // previous entry
    if (Prev != Funcs.end()) {
      if (Prev->Range.intersects(Curr->Range)) {
        // Overlapping address ranges.
        if (Prev->Range == Curr->Range) {
          // Same address range. Check if one is from debug info and the other
          // is from a symbol table. If so, then keep the one with debug info.
          // Our sorting guarantees that entries with matching address ranges
          // that have debug info are last in the sort.
          if (*Prev == *Curr) {
            // FunctionInfo entries match exactly (range, lines, inlines)
            OS << "warning: duplicate function info entries, removing "
                  "duplicate:\n"
               << *Curr << '\n';
            Curr = Funcs.erase(Prev);
          } else {
            if (!Prev->hasRichInfo() && Curr->hasRichInfo()) {
              // Same address range, one with no debug info (symbol) and the
              // next with debug info. Keep the latter.
              Curr = Funcs.erase(Prev);
            } else {
              OS << "warning: same address range contains different debug "
                 << "info. Removing:\n"
                 << *Prev << "\nIn favor of this one:\n"
                 << *Curr << "\n";
              Curr = Funcs.erase(Prev);
            }
          }
        } else {
          // print warnings about overlaps
          OS << "warning: function ranges overlap:\n"
             << *Prev << "\n"
             << *Curr << "\n";
        }
      } else if (Prev->Range.size() == 0 &&
                 Curr->Range.contains(Prev->Range.Start)) {
        OS << "warning: removing symbol:\n"
           << *Prev << "\nKeeping:\n"
           << *Curr << "\n";
        Curr = Funcs.erase(Prev);
      }
    }
    if (Curr == Funcs.end())
      break;
    Prev = Curr++;
  }

  OS << "Pruned " << NumBefore - Funcs.size() << " functions, ended with "
     << Funcs.size() << " total\n";
  return Error::success();
}

uint32_t GsymCreator::insertString(StringRef S) {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  if (S.empty())
    return 0;
  return StrTab.add(S);
}

void GsymCreator::addFunctionInfo(FunctionInfo &&FI) {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  Funcs.emplace_back(FI);
}

void GsymCreator::forEachFunctionInfo(
    std::function<bool(FunctionInfo &)> const &Callback) {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  for (auto &FI : Funcs) {
    if (!Callback(FI))
      break;
  }
}

void GsymCreator::forEachFunctionInfo(
    std::function<bool(const FunctionInfo &)> const &Callback) const {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  for (const auto &FI : Funcs) {
    if (!Callback(FI))
      break;
  }
}
<commit_msg>Fix buildbots by using memset instead of bzero.<commit_after>//===- GsymCreator.cpp ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//===----------------------------------------------------------------------===//

#include "llvm/DebugInfo/GSYM/GsymCreator.h"
#include "llvm/DebugInfo/GSYM/FileWriter.h"
#include "llvm/DebugInfo/GSYM/Header.h"
#include "llvm/DebugInfo/GSYM/LineTable.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/raw_ostream.h"

#include <algorithm>
#include <cassert>
#include <strings.h>

using namespace llvm;
using namespace gsym;

GsymCreator::GsymCreator() : StrTab(StringTableBuilder::ELF) {
  insertFile(StringRef());
}

uint32_t GsymCreator::insertFile(StringRef Path,
                                 llvm::sys::path::Style Style) {
  llvm::StringRef directory = llvm::sys::path::parent_path(Path, Style);
  llvm::StringRef filename = llvm::sys::path::filename(Path, Style);
  FileEntry FE(insertString(directory), insertString(filename));

  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  const auto NextIndex = Files.size();
  // Find FE in hash map and insert if not present.
  auto R = FileEntryToIndex.insert(std::make_pair(FE, NextIndex));
  if (R.second)
    Files.emplace_back(FE);
  return R.first->second;
}

llvm::Error GsymCreator::save(StringRef Path,
                              llvm::support::endianness ByteOrder) const {
  std::error_code EC;
  raw_fd_ostream OutStrm(Path, EC);
  if (EC)
    return llvm::errorCodeToError(EC);
  FileWriter O(OutStrm, ByteOrder);
  return encode(O);
}

llvm::Error GsymCreator::encode(FileWriter &O) const {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  if (Funcs.empty())
    return createStringError(std::errc::invalid_argument,
                             "no functions to encode");
  if (!Finalized)
    return createStringError(std::errc::invalid_argument,
                             "GsymCreator wasn't finalized prior to encoding");

  if (Funcs.size() > UINT32_MAX)
    return createStringError(std::errc::invalid_argument,
                             "too many FunctionInfos");
  const uint64_t MinAddr = Funcs.front().startAddress();
  const uint64_t MaxAddr = Funcs.back().startAddress();
  const uint64_t AddrDelta = MaxAddr - MinAddr;
  Header Hdr;
  Hdr.Magic = GSYM_MAGIC;
  Hdr.Version = GSYM_VERSION;
  Hdr.AddrOffSize = 0;
  Hdr.UUIDSize = static_cast<uint8_t>(UUID.size());
  Hdr.BaseAddress = MinAddr;
  Hdr.NumAddresses = static_cast<uint32_t>(Funcs.size());
  Hdr.StrtabOffset = 0; // We will fix this up later.
  Hdr.StrtabOffset = 0; // We will fix this up later.
  memset(Hdr.UUID, 0, sizeof(Hdr.UUID));
  if (UUID.size() > sizeof(Hdr.UUID))
    return createStringError(std::errc::invalid_argument,
                             "invalid UUID size %u", (uint32_t)UUID.size());
  // Set the address offset size correctly in the GSYM header.
  if (AddrDelta <= UINT8_MAX)
    Hdr.AddrOffSize = 1;
  else if (AddrDelta <= UINT16_MAX)
    Hdr.AddrOffSize = 2;
  else if (AddrDelta <= UINT32_MAX)
    Hdr.AddrOffSize = 4;
  else
    Hdr.AddrOffSize = 8;
  // Copy the UUID value if we have one.
  if (UUID.size() > 0)
    memcpy(Hdr.UUID, UUID.data(), UUID.size());
  // Write out the header.
  llvm::Error Err = Hdr.encode(O);
  if (Err)
    return Err;

  // Write out the address offsets.
  O.alignTo(Hdr.AddrOffSize);
  for (const auto &FuncInfo : Funcs) {
    uint64_t AddrOffset = FuncInfo.startAddress() - Hdr.BaseAddress;
    switch(Hdr.AddrOffSize) {
      case 1: O.writeU8(static_cast<uint8_t>(AddrOffset)); break;
      case 2: O.writeU16(static_cast<uint16_t>(AddrOffset)); break;
      case 4: O.writeU32(static_cast<uint32_t>(AddrOffset)); break;
      case 8: O.writeU64(AddrOffset); break;
    }
  }

  // Write out all zeros for the AddrInfoOffsets.
  O.alignTo(4);
  const off_t AddrInfoOffsetsOffset = O.tell();
  for (size_t i = 0, n = Funcs.size(); i < n; ++i)
    O.writeU32(0);

  // Write out the file table
  O.alignTo(4);
  assert(!Files.empty());
  assert(Files[0].Dir == 0);
  assert(Files[0].Base == 0);
  size_t NumFiles = Files.size();
  if (NumFiles > UINT32_MAX)
    return createStringError(std::errc::invalid_argument,
                             "too many files");
  O.writeU32(static_cast<uint32_t>(NumFiles));
  for (auto File: Files) {
      O.writeU32(File.Dir);
      O.writeU32(File.Base);
  }

  // Write out the sting table.
  const off_t StrtabOffset = O.tell();
  StrTab.write(O.get_stream());
  const off_t StrtabSize = O.tell() - StrtabOffset;
  std::vector<uint32_t> AddrInfoOffsets;

  // Write out the address infos for each function info.
  for (const auto &FuncInfo : Funcs) {
    if (Expected<uint64_t> OffsetOrErr = FuncInfo.encode(O))
        AddrInfoOffsets.push_back(OffsetOrErr.get());
    else
        return OffsetOrErr.takeError();
  }
  // Fixup the string table offset and size in the header
  O.fixup32((uint32_t)StrtabOffset, offsetof(Header, StrtabOffset));
  O.fixup32((uint32_t)StrtabSize, offsetof(Header, StrtabSize));

  // Fixup all address info offsets
  uint64_t Offset = 0;
  for (auto AddrInfoOffset: AddrInfoOffsets) {
    O.fixup32(AddrInfoOffset, AddrInfoOffsetsOffset + Offset);
    Offset += 4;
  }
  return ErrorSuccess();
}

llvm::Error GsymCreator::finalize(llvm::raw_ostream &OS) {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  if (Finalized)
    return createStringError(std::errc::invalid_argument,
                             "already finalized");
  Finalized = true;

  // Sort function infos so we can emit sorted functions.
  llvm::sort(Funcs.begin(), Funcs.end());

  // Don't let the string table indexes change by finalizing in order.
  StrTab.finalizeInOrder();

  // Remove duplicates function infos that have both entries from debug info
  // (DWARF or Breakpad) and entries from the SymbolTable.
  //
  // Also handle overlapping function. Usually there shouldn't be any, but they
  // can and do happen in some rare cases.
  //
  // (a)          (b)         (c)
  //     ^  ^       ^            ^
  //     |X |Y      |X ^         |X
  //     |  |       |  |Y        |  ^
  //     |  |       |  v         v  |Y
  //     v  v       v               v
  //
  // In (a) and (b), Y is ignored and X will be reported for the full range.
  // In (c), both functions will be included in the result and lookups for an
  // address in the intersection will return Y because of binary search.
  //
  // Note that in case of (b), we cannot include Y in the result because then
  // we wouldn't find any function for range (end of Y, end of X)
  // with binary search
  auto NumBefore = Funcs.size();
  auto Curr = Funcs.begin();
  auto Prev = Funcs.end();
  while (Curr != Funcs.end()) {
    // Can't check for overlaps or same address ranges if we don't have a
    // previous entry
    if (Prev != Funcs.end()) {
      if (Prev->Range.intersects(Curr->Range)) {
        // Overlapping address ranges.
        if (Prev->Range == Curr->Range) {
          // Same address range. Check if one is from debug info and the other
          // is from a symbol table. If so, then keep the one with debug info.
          // Our sorting guarantees that entries with matching address ranges
          // that have debug info are last in the sort.
          if (*Prev == *Curr) {
            // FunctionInfo entries match exactly (range, lines, inlines)
            OS << "warning: duplicate function info entries, removing "
                  "duplicate:\n"
               << *Curr << '\n';
            Curr = Funcs.erase(Prev);
          } else {
            if (!Prev->hasRichInfo() && Curr->hasRichInfo()) {
              // Same address range, one with no debug info (symbol) and the
              // next with debug info. Keep the latter.
              Curr = Funcs.erase(Prev);
            } else {
              OS << "warning: same address range contains different debug "
                 << "info. Removing:\n"
                 << *Prev << "\nIn favor of this one:\n"
                 << *Curr << "\n";
              Curr = Funcs.erase(Prev);
            }
          }
        } else {
          // print warnings about overlaps
          OS << "warning: function ranges overlap:\n"
             << *Prev << "\n"
             << *Curr << "\n";
        }
      } else if (Prev->Range.size() == 0 &&
                 Curr->Range.contains(Prev->Range.Start)) {
        OS << "warning: removing symbol:\n"
           << *Prev << "\nKeeping:\n"
           << *Curr << "\n";
        Curr = Funcs.erase(Prev);
      }
    }
    if (Curr == Funcs.end())
      break;
    Prev = Curr++;
  }

  OS << "Pruned " << NumBefore - Funcs.size() << " functions, ended with "
     << Funcs.size() << " total\n";
  return Error::success();
}

uint32_t GsymCreator::insertString(StringRef S) {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  if (S.empty())
    return 0;
  return StrTab.add(S);
}

void GsymCreator::addFunctionInfo(FunctionInfo &&FI) {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  Funcs.emplace_back(FI);
}

void GsymCreator::forEachFunctionInfo(
    std::function<bool(FunctionInfo &)> const &Callback) {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  for (auto &FI : Funcs) {
    if (!Callback(FI))
      break;
  }
}

void GsymCreator::forEachFunctionInfo(
    std::function<bool(const FunctionInfo &)> const &Callback) const {
  std::lock_guard<std::recursive_mutex> Guard(Mutex);
  for (const auto &FI : Funcs) {
    if (!Callback(FI))
      break;
  }
}
<|endoftext|>


<commit_before>#include "sitkTransform.h"
#include "sitkExceptionObject.h"
#include "sitkTemplateFunctions.h"

#include "itkTransformBase.h"

#include "itkIdentityTransform.h"
#include "itkTranslationTransform.h"
#include "itkScaleTransform.h"
#include "itkScaleLogarithmicTransform.h"
#include "itkQuaternionRigidTransform.h"
#include "itkVersorTransform.h"
#include "itkAffineTransform.h"
#include "itkCompositeTransform.h"

#include "itkTransformFileReader.h"
#include "itkTransformFileWriter.h"

#include <memory>

#ifndef SWIG
#ifdef SITK_HAS_STLTR1_TR1_TYPE_TRAITS
#include <tr1/type_traits>
#elif defined SITK_HAS_STLTR1_TYPE_TRAITS
#include <type_traits>
#else
#error "No system tr1 type traits available"
#endif
#endif

namespace itk
{
namespace simple
{

class PimpleTransformBase
{
public:
  virtual ~PimpleTransformBase( void ) {};

  virtual TransformBase::Pointer GetTransformBase( void ) = 0;
  virtual TransformBase::ConstPointer GetTransformBase( void ) const = 0;

  virtual unsigned int GetInputDimension( void ) const = 0;
  virtual unsigned int GetOutputDimension( void ) const = 0;

  void SetFixedParameters( const std::vector< double > &inParams )
    {
      itk::TransformBase::ParametersType p( inParams.size() );

      // todo check expected number of Fixed parameters
      std::copy( inParams.begin(), inParams.end(), p.begin() );
      this->GetTransformBase()->SetFixedParameters( p );
    }

  std::vector< double >  GetFixedParameters( void ) const
    {
      const itk::TransformBase::ParametersType &p = this->GetTransformBase()->GetFixedParameters();
      return std::vector< double >( p.begin(), p.end() );
    }

  unsigned int GetNumberOfParameters( void ) const { return this->GetTransformBase()->GetNumberOfParameters(); }

  void SetParameters( const std::vector< double > &inParams )
    {
      itk::TransformBase::ParametersType p( inParams.size() );

      // todo check expected number of Parameters
      std::copy( inParams.begin(), inParams.end(), p.begin() );
      this->GetTransformBase()->SetParameters( p );
    }
  std::vector< double > GetParameters( void ) const
    {
      const itk::TransformBase::ParametersType &p = this->GetTransformBase()->GetParameters();
      return std::vector< double >( p.begin(), p.end() );
    }

  virtual PimpleTransformBase *ShallowCopy( void ) const = 0;
  virtual PimpleTransformBase *DeepCopy( void ) const = 0;

  virtual int GetReferenceCount( ) const = 0;

  std::string ToString( void ) const
    {
      std::ostringstream out;
      this->GetTransformBase()->Print ( out );
      return out.str();
    }

  // note: the returned pointer need to be externally managed and
  // deleted
  // Also the return pointer could be this
  virtual PimpleTransformBase* AddTransform( Transform &t ) = 0;
protected:

};

template< typename TTransformType >
class PimpleTransform
  : public PimpleTransformBase
{
public:
  typedef PimpleTransform                  Self;
  typedef TTransformType                   TransformType;
  typedef typename TransformType::Pointer  TransformPointer;

  typedef itk::CompositeTransform<double, TransformType::InputSpaceDimension> CompositeTransformType;

  static const unsigned int InputDimension = TTransformType::InputSpaceDimension;
  static const unsigned int OutputDimension = TTransformType::OutputSpaceDimension;

  PimpleTransform( TransformType * p)
    {
      this->m_Transform = p;
    }

  PimpleTransform( )
    {
      this->m_Transform = TransformType::New();
    }

  virtual TransformBase::Pointer GetTransformBase( void ) { return this->m_Transform.GetPointer(); }
  virtual TransformBase::ConstPointer GetTransformBase( void ) const { return this->m_Transform.GetPointer(); }

  virtual unsigned int GetInputDimension( void ) const { return InputDimension; }
  virtual unsigned int GetOutputDimension( void ) const { return OutputDimension; }

  virtual PimpleTransformBase *ShallowCopy( void ) const
    {
      return new Self( this->m_Transform.GetPointer() );
    }

  virtual PimpleTransformBase *DeepCopy( void ) const
    {
      PimpleTransformBase *copy( new Self( this->m_Transform->Clone() ) );
      return copy;
    }

  virtual int GetReferenceCount( ) const
    {
      return this->m_Transform->GetReferenceCount();
    }

  virtual PimpleTransformBase* AddTransform( Transform &t )
    {
      if ( t.GetDimension() != TransformType::InputSpaceDimension )
        {
        sitkExceptionMacro( "Transform argument has dimension " << t.GetDimension()
                            << " does not match this dimesion of " << TransformType::InputSpaceDimension );
        }

      typename CompositeTransformType::TransformType* base =
        dynamic_cast< typename CompositeTransformType::TransformType*>( t.GetITKBase() );

      return this->AddTransform( base, typename std::tr1::is_same<TTransformType, CompositeTransformType>::type() );
    }

  PimpleTransformBase* AddTransform( typename CompositeTransformType::TransformType* &t, std::tr1::true_type isCompositeTransform )
    {
      Unused( isCompositeTransform );
      assert( t.GetDimension() == TransformType::InputSpaceDimension );

      m_Transform->AddTransform( t );
      return this;
    }

  PimpleTransformBase* AddTransform( typename CompositeTransformType::TransformType* &t, std::tr1::false_type isNotCompositeTransform )
    {
      Unused( isNotCompositeTransform );

      typename CompositeTransformType::Pointer composite = CompositeTransformType::New();
      composite->AddTransform( this->m_Transform );
      composite->AddTransform( t );
      return new PimpleTransform<CompositeTransformType>( composite );
    }

private:

  TransformPointer m_Transform;
};

//
// class Transform
//

Transform::Transform( )
  : m_PimpleTransform( NULL )
  {
    m_PimpleTransform = new PimpleTransform<itk::IdentityTransform< double, 3 > >();
  }

  Transform::Transform( unsigned int dimensions, TransformEnum type)
    : m_PimpleTransform( NULL )
  {
    if ( dimensions == 2 )
      {
      this->InternalInitialization<2 >(type);
      }
    else if ( dimensions == 3 )
      {
      this->InternalInitialization<3>(type);
      }
    else
      {
      sitkExceptionMacro("Invalid dimension for transform");
      }
  }

  Transform::~Transform()
  {
    delete m_PimpleTransform;
    this->m_PimpleTransform = NULL;
  }

  Transform::Transform( const Transform &txf )
    : m_PimpleTransform( NULL )
  {
    m_PimpleTransform = txf.m_PimpleTransform->ShallowCopy();
  }

  Transform& Transform::operator=( const Transform & txf )
  {
    // note: if txf and this are the same,the following statements
    // will be safe. It's also exception safe.
    std::auto_ptr<PimpleTransformBase> temp( txf.m_PimpleTransform->ShallowCopy() );
    delete this->m_PimpleTransform;
    this->m_PimpleTransform = temp.release();
    return *this;
  }

void Transform::MakeUniqueForWrite( void )
{
  if ( this->m_PimpleTransform->GetReferenceCount() > 1 )
    {
    std::auto_ptr<PimpleTransformBase> temp( this->m_PimpleTransform->DeepCopy() );
    delete this->m_PimpleTransform;
    this->m_PimpleTransform = temp.release();
    }
}

  template< unsigned int VDimension>
  void  Transform::InternalInitialization(  TransformEnum type, itk::TransformBase *base )
  {
    switch( type )
      {

      case sitkTranslation:
        m_PimpleTransform = new PimpleTransform<itk::TranslationTransform< double, VDimension > >();
        break;
      case sitkScale:
        m_PimpleTransform = new PimpleTransform<itk::ScaleTransform< double, VDimension > >();
        break;
      case sitkScaleLogarithmic:
        m_PimpleTransform = new PimpleTransform<itk::ScaleLogarithmicTransform< double, VDimension > >();
        break;
      case sitkQuaternionRigid:
        // todo what todo about transform which require a specific dimension
        assert( VDimension == 3 );
        m_PimpleTransform = new PimpleTransform<itk::QuaternionRigidTransform< double > >();
        break;
      case sitkVersor:
        // todo what todo about transform which require a specific dimension
        assert( VDimension == 3 );
        m_PimpleTransform = new PimpleTransform<itk::VersorTransform< double > >();
        break;
      case sitkAffine:
        m_PimpleTransform = new PimpleTransform<itk::AffineTransform< double, VDimension > >();
        break;
      case sitkComposite:
        {
        typename itk::CompositeTransform<double, VDimension>::Pointer compositeTransform;

        if ( !base )
          {
          compositeTransform = itk::CompositeTransform<double, VDimension>::New();
          }
        else
          {
          compositeTransform = dynamic_cast<itk::CompositeTransform<double, VDimension>*>( base );
          if ( !compositeTransform )
            {
            sitkExceptionMacro("Unexpectedly unable to convert to CompositeTransform" );
            }
          }

        if ( compositeTransform->IsTransformQueueEmpty() )
          {

          // Load an identity transform in case no transforms are loaded.
          typedef itk::IdentityTransform<double, VDimension> IdentityTransformType;
          typename IdentityTransformType::Pointer identityTransform = IdentityTransformType::New();

          compositeTransform->AddTransform( identityTransform );
          }
        m_PimpleTransform = new PimpleTransform<itk::CompositeTransform<double, VDimension> >( compositeTransform );
        }
        break;
      case sitkIdentity:
      default:
        m_PimpleTransform = new PimpleTransform<itk::IdentityTransform< double, VDimension > >();

      }
  }

  itk::TransformBase* Transform::GetITKBase ( void )
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->GetTransformBase();
  }

  const itk::TransformBase* Transform::GetITKBase ( void ) const
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->GetTransformBase();
  }

  unsigned int  Transform::GetDimension( void ) const
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->GetInputDimension();
  }

  void Transform::SetParameters ( const std::vector<double>& parameters )
  {
    assert( m_PimpleTransform );
    this->MakeUniqueForWrite();
    this->m_PimpleTransform->SetParameters( parameters );
  }

  std::vector<double> Transform::GetParameters( void ) const
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->GetParameters();
  }

  void Transform::SetFixedParameters ( const std::vector<double>& parameters )
  {
    assert( m_PimpleTransform );
    this->MakeUniqueForWrite();
    this->m_PimpleTransform->SetFixedParameters( parameters );
  }

  std::vector<double> Transform::GetFixedParameters( void ) const
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->GetFixedParameters();
  }

  Transform &Transform::AddTransform( Transform &t )
  {
    assert( m_PimpleTransform );
    this->MakeUniqueForWrite();
    // this returns a pointer which may be the same or a new object
    this->m_PimpleTransform  = this->m_PimpleTransform->AddTransform( t );
    return *this;
  }

  std::string Transform::ToString( void ) const
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->ToString();
  }

  Transform Transform::ReadTransform( const std::string &filename )
  {
    TransformFileReader::Pointer reader = TransformFileReader::New();
    reader->SetFileName(filename.c_str() );
    reader->Update();

    itk::TransformFileReader::TransformListType *list = reader->GetTransformList();

    if ( list->empty() )
      {
      sitkExceptionMacro( "Read transform file: \"" << filename << "\", but there appears to be not transform in the file!" );
      }
    else if( list->size() != 1 )
      {
      std::cerr << "Warning: There is more than one tranform in the file! Only using the first transform.\n";
      }

    if( list->front()->GetInputSpaceDimension() == 3
        && list->front()->GetOutputSpaceDimension() == 3 )
      {
      typedef itk::CompositeTransform<double, 3> CompositeTransformType;
      typedef CompositeTransformType::TransformType TransformType;

      CompositeTransformType::Pointer comp = CompositeTransformType::New();
      comp->ClearTransformQueue();

      TransformType* itktx = dynamic_cast<TransformType*>(list->front().GetPointer());

      if (itktx)
        {
        comp->AddTransform( itktx );
        }

      return Transform( comp.GetPointer() );
      }
    else if( list->front()->GetInputSpaceDimension() == 2
        && list->front()->GetOutputSpaceDimension() == 2)
      {
      typedef itk::CompositeTransform<double, 2> CompositeTransformType;
      typedef CompositeTransformType::TransformType TransformType;

      CompositeTransformType::Pointer comp = CompositeTransformType::New();
      comp->ClearTransformQueue();

      TransformType* itktx = dynamic_cast<TransformType*>(list->front().GetPointer());

      if (itktx)
        {
        comp->AddTransform( itktx );
        }

      return Transform( comp.GetPointer() );
      }
    else
      {
      sitkExceptionMacro( "Transform with InputSpaceDimension: " <<  list->front()->GetInputSpaceDimension()
                          << " and OutputSpaceDimension: " << list->front()->GetOutputSpaceDimension()
                          << "is not supported." );
      }
  }

  void Transform::WriteTransform( const std::string &filename ) const
  {
    Self::WriteTransform( *this, filename );
  }

  // write
  void Transform::WriteTransform( const Transform &transform, const std::string &filename)
  {
    itk::TransformFileWriter::Pointer writer = itk::TransformFileWriter::New();
    writer->SetFileName(filename.c_str());
    writer->SetInput( transform.GetITKBase() );
    writer->Update();
  }

}
}
<commit_msg>Throw exception for 3D only transforms<commit_after>#include "sitkTransform.h"
#include "sitkExceptionObject.h"
#include "sitkTemplateFunctions.h"

#include "itkTransformBase.h"

#include "itkIdentityTransform.h"
#include "itkTranslationTransform.h"
#include "itkScaleTransform.h"
#include "itkScaleLogarithmicTransform.h"
#include "itkQuaternionRigidTransform.h"
#include "itkVersorTransform.h"
#include "itkAffineTransform.h"
#include "itkCompositeTransform.h"

#include "itkTransformFileReader.h"
#include "itkTransformFileWriter.h"

#include <memory>

#ifndef SWIG
#ifdef SITK_HAS_STLTR1_TR1_TYPE_TRAITS
#include <tr1/type_traits>
#elif defined SITK_HAS_STLTR1_TYPE_TRAITS
#include <type_traits>
#else
#error "No system tr1 type traits available"
#endif
#endif

namespace itk
{
namespace simple
{

// This is a base class of the private implementatino of the transform
// class.
//
// The interface provide virutal method and other generic methods to
// the concrete ITK transform type, there by provide encapsulation and
// a uniform interface
class PimpleTransformBase
{
public:
  virtual ~PimpleTransformBase( void ) {};

  // Get Access to the internal ITK transform class
  virtual TransformBase::Pointer GetTransformBase( void ) = 0;
  virtual TransformBase::ConstPointer GetTransformBase( void ) const = 0;

  // general methods to get information about the internal class
  virtual unsigned int GetInputDimension( void ) const = 0;
  virtual unsigned int GetOutputDimension( void ) const = 0;

  // Set the fixed parameter for the transform, converting from the
  // simpleITK std::vector to the ITK's array.
  void SetFixedParameters( const std::vector< double > &inParams )
    {
      itk::TransformBase::ParametersType p( inParams.size() );

      // todo check expected number of Fixed parameters
      std::copy( inParams.begin(), inParams.end(), p.begin() );
      this->GetTransformBase()->SetFixedParameters( p );
    }

  // Get the fixed parameters form the transform
  std::vector< double >  GetFixedParameters( void ) const
    {
      const itk::TransformBase::ParametersType &p = this->GetTransformBase()->GetFixedParameters();
      return std::vector< double >( p.begin(), p.end() );
    }

  unsigned int GetNumberOfParameters( void ) const { return this->GetTransformBase()->GetNumberOfParameters(); }

  void SetParameters( const std::vector< double > &inParams )
    {
      itk::TransformBase::ParametersType p( inParams.size() );

      // todo check expected number of Parameters
      std::copy( inParams.begin(), inParams.end(), p.begin() );
      this->GetTransformBase()->SetParameters( p );
    }
  std::vector< double > GetParameters( void ) const
    {
      const itk::TransformBase::ParametersType &p = this->GetTransformBase()->GetParameters();
      return std::vector< double >( p.begin(), p.end() );
    }

  virtual PimpleTransformBase *ShallowCopy( void ) const = 0;
  virtual PimpleTransformBase *DeepCopy( void ) const = 0;

  virtual int GetReferenceCount( ) const = 0;

  std::string ToString( void ) const
    {
      std::ostringstream out;
      this->GetTransformBase()->Print ( out );
      return out.str();
    }

  // note: the returned pointer need to be externally managed and
  // deleted
  // Also the return pointer could be this
  virtual PimpleTransformBase* AddTransform( Transform &t ) = 0;
protected:

};

template< typename TTransformType >
class PimpleTransform
  : public PimpleTransformBase
{
public:
  typedef PimpleTransform                  Self;
  typedef TTransformType                   TransformType;
  typedef typename TransformType::Pointer  TransformPointer;

  typedef itk::CompositeTransform<double, TransformType::InputSpaceDimension> CompositeTransformType;

  static const unsigned int InputDimension = TTransformType::InputSpaceDimension;
  static const unsigned int OutputDimension = TTransformType::OutputSpaceDimension;

  PimpleTransform( TransformType * p)
    {
      this->m_Transform = p;
    }

  PimpleTransform( )
    {
      this->m_Transform = TransformType::New();
    }

  PimpleTransform( Self &s )
    : m_Transform( s.m_Transform )
    {}

  PimpleTransform &operator=( const PimpleTransform &s )
    {
      m_Transform = s.m_Transform;
    }

  virtual TransformBase::Pointer GetTransformBase( void ) { return this->m_Transform.GetPointer(); }
  virtual TransformBase::ConstPointer GetTransformBase( void ) const { return this->m_Transform.GetPointer(); }

  virtual unsigned int GetInputDimension( void ) const { return InputDimension; }
  virtual unsigned int GetOutputDimension( void ) const { return OutputDimension; }

  virtual PimpleTransformBase *ShallowCopy( void ) const
    {
      return new Self( this->m_Transform.GetPointer() );
    }

  virtual PimpleTransformBase *DeepCopy( void ) const
    {
      PimpleTransformBase *copy( new Self( this->m_Transform->Clone() ) );
      return copy;
    }

  virtual int GetReferenceCount( ) const
    {
      return this->m_Transform->GetReferenceCount();
    }

  virtual PimpleTransformBase* AddTransform( Transform &t )
    {
      if ( t.GetDimension() != TransformType::InputSpaceDimension )
        {
        sitkExceptionMacro( "Transform argument has dimension " << t.GetDimension()
                            << " does not match this dimesion of " << TransformType::InputSpaceDimension );
        }

      typename CompositeTransformType::TransformType* base =
        dynamic_cast< typename CompositeTransformType::TransformType*>( t.GetITKBase() );

      return this->AddTransform( base, typename std::tr1::is_same<TTransformType, CompositeTransformType>::type() );
    }

  PimpleTransformBase* AddTransform( typename CompositeTransformType::TransformType* &t, std::tr1::true_type isCompositeTransform )
    {
      Unused( isCompositeTransform );
      assert( t.GetDimension() == TransformType::InputSpaceDimension );

      m_Transform->AddTransform( t );
      return this;
    }

  PimpleTransformBase* AddTransform( typename CompositeTransformType::TransformType* &t, std::tr1::false_type isNotCompositeTransform )
    {
      Unused( isNotCompositeTransform );

      typename CompositeTransformType::Pointer composite = CompositeTransformType::New();
      composite->AddTransform( this->m_Transform );
      composite->AddTransform( t );
      return new PimpleTransform<CompositeTransformType>( composite );
    }

private:

  TransformPointer m_Transform;
};

//
// class Transform
//

Transform::Transform( )
  : m_PimpleTransform( NULL )
  {
    m_PimpleTransform = new PimpleTransform<itk::IdentityTransform< double, 3 > >();
  }

  Transform::Transform( unsigned int dimensions, TransformEnum type)
    : m_PimpleTransform( NULL )
  {
    if ( dimensions == 2 )
      {
      this->InternalInitialization<2 >(type);
      }
    else if ( dimensions == 3 )
      {
      this->InternalInitialization<3>(type);
      }
    else
      {
      sitkExceptionMacro("Invalid dimension for transform");
      }
  }

  Transform::~Transform()
  {
    delete m_PimpleTransform;
    this->m_PimpleTransform = NULL;
  }

  Transform::Transform( const Transform &txf )
    : m_PimpleTransform( NULL )
  {
    m_PimpleTransform = txf.m_PimpleTransform->ShallowCopy();
  }

  Transform& Transform::operator=( const Transform & txf )
  {
    // note: if txf and this are the same,the following statements
    // will be safe. It's also exception safe.
    std::auto_ptr<PimpleTransformBase> temp( txf.m_PimpleTransform->ShallowCopy() );
    delete this->m_PimpleTransform;
    this->m_PimpleTransform = temp.release();
    return *this;
  }

void Transform::MakeUniqueForWrite( void )
{
  if ( this->m_PimpleTransform->GetReferenceCount() > 1 )
    {
    std::auto_ptr<PimpleTransformBase> temp( this->m_PimpleTransform->DeepCopy() );
    delete this->m_PimpleTransform;
    this->m_PimpleTransform = temp.release();
    }
}

  template< unsigned int VDimension>
  void  Transform::InternalInitialization(  TransformEnum type, itk::TransformBase *base )
  {
    switch( type )
      {

      case sitkTranslation:
        m_PimpleTransform = new PimpleTransform<itk::TranslationTransform< double, VDimension > >();
        break;
      case sitkScale:
        m_PimpleTransform = new PimpleTransform<itk::ScaleTransform< double, VDimension > >();
        break;
      case sitkScaleLogarithmic:
        m_PimpleTransform = new PimpleTransform<itk::ScaleLogarithmicTransform< double, VDimension > >();
        break;
      case sitkQuaternionRigid:
        if( VDimension != 3)
          {
          sitkExceptionMacro( "A sitkQuaternionRigid Transform only works for 3D!");
          }

        m_PimpleTransform = new PimpleTransform<itk::QuaternionRigidTransform< double > >();
        break;
      case sitkVersor:
        if( VDimension != 3)
          {
          sitkExceptionMacro( "A sitkVersor Transform only works for 3D!");
          }

        m_PimpleTransform = new PimpleTransform<itk::VersorTransform< double > >();
        break;
      case sitkAffine:
        m_PimpleTransform = new PimpleTransform<itk::AffineTransform< double, VDimension > >();
        break;
      case sitkComposite:
        {
        typename itk::CompositeTransform<double, VDimension>::Pointer compositeTransform;

        if ( !base )
          {
          compositeTransform = itk::CompositeTransform<double, VDimension>::New();
          }
        else
          {
          compositeTransform = dynamic_cast<itk::CompositeTransform<double, VDimension>*>( base );
          if ( !compositeTransform )
            {
            sitkExceptionMacro("Unexpectedly unable to convert to CompositeTransform" );
            }
          }

        if ( compositeTransform->IsTransformQueueEmpty() )
          {

          // Load an identity transform in case no transforms are loaded.
          typedef itk::IdentityTransform<double, VDimension> IdentityTransformType;
          typename IdentityTransformType::Pointer identityTransform = IdentityTransformType::New();

          compositeTransform->AddTransform( identityTransform );
          }
        m_PimpleTransform = new PimpleTransform<itk::CompositeTransform<double, VDimension> >( compositeTransform );
        }
        break;
      case sitkIdentity:
      default:
        m_PimpleTransform = new PimpleTransform<itk::IdentityTransform< double, VDimension > >();

      }
  }

  itk::TransformBase* Transform::GetITKBase ( void )
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->GetTransformBase();
  }

  const itk::TransformBase* Transform::GetITKBase ( void ) const
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->GetTransformBase();
  }

  unsigned int  Transform::GetDimension( void ) const
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->GetInputDimension();
  }

  void Transform::SetParameters ( const std::vector<double>& parameters )
  {
    assert( m_PimpleTransform );
    this->MakeUniqueForWrite();
    this->m_PimpleTransform->SetParameters( parameters );
  }

  std::vector<double> Transform::GetParameters( void ) const
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->GetParameters();
  }

  void Transform::SetFixedParameters ( const std::vector<double>& parameters )
  {
    assert( m_PimpleTransform );
    this->MakeUniqueForWrite();
    this->m_PimpleTransform->SetFixedParameters( parameters );
  }

  std::vector<double> Transform::GetFixedParameters( void ) const
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->GetFixedParameters();
  }

  Transform &Transform::AddTransform( Transform &t )
  {
    assert( m_PimpleTransform );
    this->MakeUniqueForWrite();
    // this returns a pointer which may be the same or a new object
    this->m_PimpleTransform  = this->m_PimpleTransform->AddTransform( t );
    return *this;
  }

  std::string Transform::ToString( void ) const
  {
    assert( m_PimpleTransform );
    return this->m_PimpleTransform->ToString();
  }

  Transform Transform::ReadTransform( const std::string &filename )
  {
    TransformFileReader::Pointer reader = TransformFileReader::New();
    reader->SetFileName(filename.c_str() );
    reader->Update();

    itk::TransformFileReader::TransformListType *list = reader->GetTransformList();

    if ( list->empty() )
      {
      sitkExceptionMacro( "Read transform file: \"" << filename << "\", but there appears to be not transform in the file!" );
      }
    else if( list->size() != 1 )
      {
      std::cerr << "Warning: There is more than one tranform in the file! Only using the first transform.\n";
      }

    if( list->front()->GetInputSpaceDimension() == 3
        && list->front()->GetOutputSpaceDimension() == 3 )
      {
      typedef itk::CompositeTransform<double, 3> CompositeTransformType;
      typedef CompositeTransformType::TransformType TransformType;

      CompositeTransformType::Pointer comp = CompositeTransformType::New();
      comp->ClearTransformQueue();

      TransformType* itktx = dynamic_cast<TransformType*>(list->front().GetPointer());

      if (itktx)
        {
        comp->AddTransform( itktx );
        }

      return Transform( comp.GetPointer() );
      }
    else if( list->front()->GetInputSpaceDimension() == 2
        && list->front()->GetOutputSpaceDimension() == 2)
      {
      typedef itk::CompositeTransform<double, 2> CompositeTransformType;
      typedef CompositeTransformType::TransformType TransformType;

      CompositeTransformType::Pointer comp = CompositeTransformType::New();
      comp->ClearTransformQueue();

      TransformType* itktx = dynamic_cast<TransformType*>(list->front().GetPointer());

      if (itktx)
        {
        comp->AddTransform( itktx );
        }

      return Transform( comp.GetPointer() );
      }
    else
      {
      sitkExceptionMacro( "Transform with InputSpaceDimension: " <<  list->front()->GetInputSpaceDimension()
                          << " and OutputSpaceDimension: " << list->front()->GetOutputSpaceDimension()
                          << "is not supported." );
      }
  }

  void Transform::WriteTransform( const std::string &filename ) const
  {
    Self::WriteTransform( *this, filename );
  }

  // write
  void Transform::WriteTransform( const Transform &transform, const std::string &filename)
  {
    itk::TransformFileWriter::Pointer writer = itk::TransformFileWriter::New();
    writer->SetFileName(filename.c_str());
    writer->SetInput( transform.GetITKBase() );
    writer->Update();
  }

}
}
<|endoftext|>


<commit_before>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "IncrementalJIT.h"

#include "IncrementalExecutor.h"

#include "llvm/Support/DynamicLibrary.h"

using namespace llvm;

namespace {
// Forward cxa_atexit for global d'tors.
static void local_cxa_atexit(void (*func) (void*), void* arg, void* dso) {
  cling::IncrementalExecutor* exe = (cling::IncrementalExecutor*)dso;
  exe->AddAtExitFunc(func, arg);
}

///\brief Memory manager providing the lop-level link to the
/// IncrementalExecutor, handles missing or special / replaced symbols.
class ClingMemoryManager: public SectionMemoryManager {
  cling::IncrementalExecutor& m_exe;

public:
  ClingMemoryManager(cling::IncrementalExecutor& Exe):
    m_exe(Exe) {}

  /// This method returns the address of the specified function or variable
  /// that could not be resolved by getSymbolAddress() or by resolving
  /// possible weak symbols by the ExecutionEngine.
  /// It is used to resolve symbols during module linking.
  uint64_t getMissingSymbolAddress(const std::string &Name) override {
    return (uint64_t) m_exe.NotifyLazyFunctionCreators(Name);
  }

  ///\brief Simply wraps the base class's function setting AbortOnFailure
  /// to false and instead using the error handling mechanism to report it.
  void* getPointerToNamedFunction(const std::string &Name,
                                  bool /*AbortOnFailure*/ =true) override {
    return SectionMemoryManager::getPointerToNamedFunction(Name, false);
  }
};
} // unnamed namespace

namespace cling {

///\brief Memory manager for the OrcJIT layers to resolve symbols from the
/// common IncrementalJIT. I.e. the master of the Orcs.
/// Each ObjectLayer instance has one Azog object.
class Azog: public RTDyldMemoryManager {
  cling::IncrementalJIT& m_jit;

public:
  Azog(cling::IncrementalJIT& Jit): m_jit(Jit) {}

  RTDyldMemoryManager* getExeMM() const { return m_jit.m_ExeMM.get(); }

  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
                               unsigned SectionID,
                               StringRef SectionName) override {
    uint8_t *Addr =
      getExeMM()->allocateCodeSection(Size, Alignment, SectionID, SectionName);
    m_jit.m_SectionsAllocatedSinceLastLoad.insert(Addr);
    return Addr;
  }

  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
                               unsigned SectionID, StringRef SectionName,
                               bool IsReadOnly) override {
    uint8_t *Addr = getExeMM()->allocateDataSection(Size, Alignment, SectionID,
                                                    SectionName, IsReadOnly);
    m_jit.m_SectionsAllocatedSinceLastLoad.insert(Addr);
    return Addr;
  }

  void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO,
                              uintptr_t DataSizeRW) override {
    return getExeMM()->reserveAllocationSpace(CodeSize, DataSizeRO, DataSizeRW);
  }

  bool needsToReserveAllocationSpace() override {
    return getExeMM()->needsToReserveAllocationSpace();
  }

  void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
                        size_t Size) override {
    return getExeMM()->registerEHFrames(Addr, LoadAddr, Size);
  }

  void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
                          size_t Size) override {
    return getExeMM()->deregisterEHFrames(Addr, LoadAddr, Size);
  }

  uint64_t getSymbolAddress(const std::string &Name) override {
    return m_jit.getSymbolAddressWithoutMangling(Name);
  }

  void *getPointerToNamedFunction(const std::string &Name,
                                  bool AbortOnFailure = true) override {
    return getExeMM()->getPointerToNamedFunction(Name, AbortOnFailure);
  }

  void notifyObjectLoaded(ExecutionEngine *EE,
                          const object::ObjectFile &O) override {
    return getExeMM()->notifyObjectLoaded(EE, O);
  }

  bool finalizeMemory(std::string *ErrMsg = nullptr) override {
    // Each set of objects loaded will be finalized exactly once, but since
    // symbol lookup during relocation may recursively trigger the
    // loading/relocation of other modules, and since we're forwarding all
    // finalizeMemory calls to a single underlying memory manager, we need to
    // defer forwarding the call on until all necessary objects have been
    // loaded. Otherwise, during the relocation of a leaf object, we will end
    // up finalizing memory, causing a crash further up the stack when we
    // attempt to apply relocations to finalized memory.
    // To avoid finalizing too early, look at how many objects have been
    // loaded but not yet finalized. This is a bit of a hack that relies on
    // the fact that we're lazily emitting object files: The only way you can
    // get more than one set of objects loaded but not yet finalized is if
    // they were loaded during relocation of another set.
    if (m_jit.m_UnfinalizedSections.size() == 1)
      return getExeMM()->finalizeMemory(ErrMsg);
    return false;
  };

  /// This method returns the address of the specified function or variable
  /// that could not be resolved by getSymbolAddress() or by resolving
  /// possible weak symbols by the ExecutionEngine.
  /// It is used to resolve symbols during module linking.
  uint64_t getMissingSymbolAddress(const std::string &Name) override {
    return (uint64_t) m_jit.getParent().NotifyLazyFunctionCreators(Name);
  }

}; // class Azog

IncrementalJIT::IncrementalJIT(IncrementalExecutor& exe,
                               std::unique_ptr<TargetMachine> TM):
  m_Parent(exe),
  m_TM(std::move(TM)),
  m_ExeMM(std::move(llvm::make_unique<ClingMemoryManager>(m_Parent))),
  m_Mang(m_TM->getDataLayout()),
  m_NotifyObjectLoaded(*this), m_NotifyFinalized(*this),
  m_ObjectLayer(ObjectLayerT::CreateRTDyldMMFtor(), m_NotifyObjectLoaded,
                m_NotifyFinalized),
  m_CompileLayer(m_ObjectLayer, SimpleCompiler(*m_TM)),
  m_LazyEmitLayer(m_CompileLayer) {

  // Enable JIT symbol resolution from the binary.
  llvm::sys::DynamicLibrary::LoadLibraryPermanently(0, 0);

// #if MCJIT
//   llvm::EngineBuilder builder(std::move(m));

//   std::string errMsg;
//   builder.setErrorStr(&errMsg);
//   builder.setOptLevel(llvm::CodeGenOpt::Less);
//   builder.setEngineKind(llvm::EngineKind::JIT);
//   std::unique_ptr<llvm::RTDyldMemoryManager>
//     MemMan(new ClingMemoryManager(*this));
//   builder.setMCJITMemoryManager(std::move(MemMan));

//   // EngineBuilder uses default c'ted TargetOptions, too:
//   llvm::TargetOptions TargetOpts;
//   TargetOpts.NoFramePointerElim = 1;
//   TargetOpts.JITEmitDebugInfo = 1;

//   builder.setTargetOptions(TargetOpts);

//   m_engine.reset(builder.create());
//   assert(m_engine && "Cannot create module!");
// #endif
}

uint64_t IncrementalJIT::getSymbolAddressWithoutMangling(llvm::StringRef Name) {
  if (Name == "__cxa_atexit") {
    // Rewire __cxa_atexit to ~Interpreter(), thus also global destruction
    // coming from the JIT.
    return (uint64_t)&local_cxa_atexit;
  } else if (Name == "__dso_handle") {
    // Provide IncrementalExecutor as the third argument to __cxa_atexit.
    return (uint64_t)&m_Parent;
  }
  if (uint64_t Addr = m_ExeMM->getSymbolAddress(Name))
    return Addr;
  if (uint64_t Addr = m_LazyEmitLayer.getSymbolAddress(Name, false))
    return Addr;

  return 0;
}

size_t IncrementalJIT::addModules(std::vector<llvm::Module*>&& modules) {
  // If this module doesn't have a DataLayout attached then attach the
  // default.
  for (auto&& mod: modules) {
    if (!mod->getDataLayout())
      mod->setDataLayout(m_TM->getDataLayout());
  }

  ModuleSetHandleT MSHandle
    = m_LazyEmitLayer.addModuleSet(std::move(modules),
                                   llvm::make_unique<Azog>(*this));
  m_UnloadPoints.push_back(MSHandle);
  return m_UnloadPoints.size() - 1;
}

// void* IncrementalJIT::finalizeMemory() {
//   for (auto &P : UnfinalizedSections)
//     if (P.second.count(LocalAddress))
//       ObjectLayer.mapSectionAddress(P.first, LocalAddress, TargetAddress);
// }

void IncrementalJIT::removeModules(size_t handle) {
  m_LazyEmitLayer.removeModuleSet(m_UnloadPoints[handle]);
}

}// end namespace cling
<commit_msg>MacOS adds an extra "_" in front of symbol names.<commit_after>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "IncrementalJIT.h"

#include "IncrementalExecutor.h"

#include "llvm/Support/DynamicLibrary.h"

using namespace llvm;

namespace {
// Forward cxa_atexit for global d'tors.
static void local_cxa_atexit(void (*func) (void*), void* arg, void* dso) {
  cling::IncrementalExecutor* exe = (cling::IncrementalExecutor*)dso;
  exe->AddAtExitFunc(func, arg);
}

///\brief Memory manager providing the lop-level link to the
/// IncrementalExecutor, handles missing or special / replaced symbols.
class ClingMemoryManager: public SectionMemoryManager {
  cling::IncrementalExecutor& m_exe;

public:
  ClingMemoryManager(cling::IncrementalExecutor& Exe):
    m_exe(Exe) {}

  /// This method returns the address of the specified function or variable
  /// that could not be resolved by getSymbolAddress() or by resolving
  /// possible weak symbols by the ExecutionEngine.
  /// It is used to resolve symbols during module linking.
  uint64_t getMissingSymbolAddress(const std::string &Name) override {
    return (uint64_t) m_exe.NotifyLazyFunctionCreators(Name);
  }

  ///\brief Simply wraps the base class's function setting AbortOnFailure
  /// to false and instead using the error handling mechanism to report it.
  void* getPointerToNamedFunction(const std::string &Name,
                                  bool /*AbortOnFailure*/ =true) override {
    return SectionMemoryManager::getPointerToNamedFunction(Name, false);
  }
};
} // unnamed namespace

namespace cling {

///\brief Memory manager for the OrcJIT layers to resolve symbols from the
/// common IncrementalJIT. I.e. the master of the Orcs.
/// Each ObjectLayer instance has one Azog object.
class Azog: public RTDyldMemoryManager {
  cling::IncrementalJIT& m_jit;

public:
  Azog(cling::IncrementalJIT& Jit): m_jit(Jit) {}

  RTDyldMemoryManager* getExeMM() const { return m_jit.m_ExeMM.get(); }

  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
                               unsigned SectionID,
                               StringRef SectionName) override {
    uint8_t *Addr =
      getExeMM()->allocateCodeSection(Size, Alignment, SectionID, SectionName);
    m_jit.m_SectionsAllocatedSinceLastLoad.insert(Addr);
    return Addr;
  }

  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
                               unsigned SectionID, StringRef SectionName,
                               bool IsReadOnly) override {
    uint8_t *Addr = getExeMM()->allocateDataSection(Size, Alignment, SectionID,
                                                    SectionName, IsReadOnly);
    m_jit.m_SectionsAllocatedSinceLastLoad.insert(Addr);
    return Addr;
  }

  void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO,
                              uintptr_t DataSizeRW) override {
    return getExeMM()->reserveAllocationSpace(CodeSize, DataSizeRO, DataSizeRW);
  }

  bool needsToReserveAllocationSpace() override {
    return getExeMM()->needsToReserveAllocationSpace();
  }

  void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
                        size_t Size) override {
    return getExeMM()->registerEHFrames(Addr, LoadAddr, Size);
  }

  void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
                          size_t Size) override {
    return getExeMM()->deregisterEHFrames(Addr, LoadAddr, Size);
  }

  uint64_t getSymbolAddress(const std::string &Name) override {
    return m_jit.getSymbolAddressWithoutMangling(Name);
  }

  void *getPointerToNamedFunction(const std::string &Name,
                                  bool AbortOnFailure = true) override {
    return getExeMM()->getPointerToNamedFunction(Name, AbortOnFailure);
  }

  void notifyObjectLoaded(ExecutionEngine *EE,
                          const object::ObjectFile &O) override {
    return getExeMM()->notifyObjectLoaded(EE, O);
  }

  bool finalizeMemory(std::string *ErrMsg = nullptr) override {
    // Each set of objects loaded will be finalized exactly once, but since
    // symbol lookup during relocation may recursively trigger the
    // loading/relocation of other modules, and since we're forwarding all
    // finalizeMemory calls to a single underlying memory manager, we need to
    // defer forwarding the call on until all necessary objects have been
    // loaded. Otherwise, during the relocation of a leaf object, we will end
    // up finalizing memory, causing a crash further up the stack when we
    // attempt to apply relocations to finalized memory.
    // To avoid finalizing too early, look at how many objects have been
    // loaded but not yet finalized. This is a bit of a hack that relies on
    // the fact that we're lazily emitting object files: The only way you can
    // get more than one set of objects loaded but not yet finalized is if
    // they were loaded during relocation of another set.
    if (m_jit.m_UnfinalizedSections.size() == 1)
      return getExeMM()->finalizeMemory(ErrMsg);
    return false;
  };

  /// This method returns the address of the specified function or variable
  /// that could not be resolved by getSymbolAddress() or by resolving
  /// possible weak symbols by the ExecutionEngine.
  /// It is used to resolve symbols during module linking.
  uint64_t getMissingSymbolAddress(const std::string &Name) override {
    return (uint64_t) m_jit.getParent().NotifyLazyFunctionCreators(Name);
  }

}; // class Azog

IncrementalJIT::IncrementalJIT(IncrementalExecutor& exe,
                               std::unique_ptr<TargetMachine> TM):
  m_Parent(exe),
  m_TM(std::move(TM)),
  m_ExeMM(std::move(llvm::make_unique<ClingMemoryManager>(m_Parent))),
  m_Mang(m_TM->getDataLayout()),
  m_NotifyObjectLoaded(*this), m_NotifyFinalized(*this),
  m_ObjectLayer(ObjectLayerT::CreateRTDyldMMFtor(), m_NotifyObjectLoaded,
                m_NotifyFinalized),
  m_CompileLayer(m_ObjectLayer, SimpleCompiler(*m_TM)),
  m_LazyEmitLayer(m_CompileLayer) {

  // Enable JIT symbol resolution from the binary.
  llvm::sys::DynamicLibrary::LoadLibraryPermanently(0, 0);

// #if MCJIT
//   llvm::EngineBuilder builder(std::move(m));

//   std::string errMsg;
//   builder.setErrorStr(&errMsg);
//   builder.setOptLevel(llvm::CodeGenOpt::Less);
//   builder.setEngineKind(llvm::EngineKind::JIT);
//   std::unique_ptr<llvm::RTDyldMemoryManager>
//     MemMan(new ClingMemoryManager(*this));
//   builder.setMCJITMemoryManager(std::move(MemMan));

//   // EngineBuilder uses default c'ted TargetOptions, too:
//   llvm::TargetOptions TargetOpts;
//   TargetOpts.NoFramePointerElim = 1;
//   TargetOpts.JITEmitDebugInfo = 1;

//   builder.setTargetOptions(TargetOpts);

//   m_engine.reset(builder.create());
//   assert(m_engine && "Cannot create module!");
// #endif
}

uint64_t IncrementalJIT::getSymbolAddressWithoutMangling(llvm::StringRef Name) {
#ifdef __APPLE__
  // Apple adds an extra '_'
# define MANGLE_PREFIX "_"
#else
# define MANGLE_PREFIX ""
#endif
  if (Name == MANGLE_PREFIX "__cxa_atexit") {
    // Rewire __cxa_atexit to ~Interpreter(), thus also global destruction
    // coming from the JIT.
    return (uint64_t)&local_cxa_atexit;
  } else if (Name == MANGLE_PREFIX "__dso_handle") {
    // Provide IncrementalExecutor as the third argument to __cxa_atexit.
    return (uint64_t)&m_Parent;
  }
#undef MANGLE_PREFIX
  if (uint64_t Addr = m_ExeMM->getSymbolAddress(Name))
    return Addr;
  if (uint64_t Addr = m_LazyEmitLayer.getSymbolAddress(Name, false))
    return Addr;

  return 0;
}

size_t IncrementalJIT::addModules(std::vector<llvm::Module*>&& modules) {
  // If this module doesn't have a DataLayout attached then attach the
  // default.
  for (auto&& mod: modules) {
    if (!mod->getDataLayout())
      mod->setDataLayout(m_TM->getDataLayout());
  }

  ModuleSetHandleT MSHandle
    = m_LazyEmitLayer.addModuleSet(std::move(modules),
                                   llvm::make_unique<Azog>(*this));
  m_UnloadPoints.push_back(MSHandle);
  return m_UnloadPoints.size() - 1;
}

// void* IncrementalJIT::finalizeMemory() {
//   for (auto &P : UnfinalizedSections)
//     if (P.second.count(LocalAddress))
//       ObjectLayer.mapSectionAddress(P.first, LocalAddress, TargetAddress);
// }

void IncrementalJIT::removeModules(size_t handle) {
  m_LazyEmitLayer.removeModuleSet(m_UnloadPoints[handle]);
}

}// end namespace cling
<|endoftext|>


<commit_before>// Copyright 2011 Michael Steinert. All rights reserved.
// 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.
//     * The names of the copyright holder, the author, nor any 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.

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <cstring>
#include "moka/typed-array.h"
#include "moka/module.h"
#include <sstream>

namespace moka {

TypedArray::TypedArray()
  : length_(0) {}

// Public interface
v8::Handle<v8::FunctionTemplate> TypedArray::GetTemplate() {
  static v8::Persistent<v8::FunctionTemplate> templ_;
  if (!templ_.IsEmpty()) {
    return templ_;
  }
  v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
  templ->SetClassName(v8::String::NewSymbol("TypedArray"));
  templ->Inherit(ArrayBufferView::GetTemplate());
  // Properties
  templ->PrototypeTemplate()->SetAccessor(v8::String::NewSymbol("length"),
      Length);
  // Methods
  templ->PrototypeTemplate()->Set(v8::String::NewSymbol("get"),
      v8::FunctionTemplate::New(Get)->GetFunction());
  templ->PrototypeTemplate()->Set(v8::String::NewSymbol("set"),
      v8::FunctionTemplate::New(Set)->GetFunction());
  templ->PrototypeTemplate()->Set(v8::String::NewSymbol("subarray"),
      v8::FunctionTemplate::New(SubArray)->GetFunction());
  templ_ = v8::Persistent<v8::FunctionTemplate>::New(templ);
  return templ_;
}

// Private V8 interface
v8::Handle<v8::Value> TypedArray::Length(v8::Local<v8::String> property,
    const v8::AccessorInfo &info) {
  return v8::Uint32::New(static_cast<TypedArray*>(
        info.This()->GetPointerFromInternalField(0))->GetLength());
}

v8::Handle<v8::Value> TypedArray::Get(const v8::Arguments& arguments) {
  switch (arguments.Length()) {
  case 1:
    if (arguments[0]->IsUint32()) {
      TypedArray* self = static_cast<TypedArray*>(
          arguments.This()->GetPointerFromInternalField(0));
      uint32_t index = arguments[0]->ToUint32()->Value();
      if (index < self->GetLength()) {
        return arguments.This()->Get(index);
      }
      return v8::Undefined();
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument one must be an unsigned long")));
    }
  default:
    return v8::ThrowException(v8::Exception::TypeError(
          v8::String::New("One argument is required")));
  }
}

v8::Handle<v8::Value> TypedArray::Set(const v8::Arguments& arguments) {
  TypedArray* self = static_cast<TypedArray*>(
      arguments.This()->GetPointerFromInternalField(0));
  uint32_t offset = 0;
  switch (arguments.Length()) {
  case 2:
    if (arguments[0]->IsUint32()) {
      uint32_t index = arguments[0]->ToUint32()->Value();
      if (index < self->GetLength()) {
        arguments.This()->Set(index, arguments[1]);
      }
      return v8::Undefined();
    } else {
      if (arguments[1]->IsUint32()) {
        offset = arguments[1]->ToUint32()->Value();
      } else {
        return v8::ThrowException(v8::Exception::TypeError(
              v8::String::New("Argument two must be an unsigned long")));
      }
    }
    // Fall through
  case 1:
    if (arguments[0]->IsObject()) {
      v8::Handle<v8::Object> object = arguments[0]->ToObject();
      if (object->IsArray()) {
        v8::Array* array = v8::Array::Cast(*arguments[0]);
        if (offset + array->Length() > self->GetLength()) {
          return v8::ThrowException(v8::Exception::RangeError(
                v8::String::New("Offset is out of range")));
        }
        for (uint32_t index = 0; index < self->GetLength(); ++index) {
          arguments.This()->Set(index + offset, array->Get(index));
        }
      } else if (GetTemplate()->HasInstance(object)) {
        TypedArray* that = static_cast<TypedArray*>(
            object->GetPointerFromInternalField(0));
        if (offset + that->GetLength() > self->GetLength()) {
          return v8::ThrowException(v8::Exception::RangeError(
                v8::String::New("Offset is out of range")));
        }
        for (uint32_t index = 0; index < self->GetLength(); ++index) {
          arguments.This()->Set(index + offset, object->Get(index));
        }
      } else {
        return v8::ThrowException(v8::Exception::TypeError(
              v8::String::New("Argument one must be an array")));
      }
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument one must be an object")));
    }
    break;
  default:
    return v8::ThrowException(v8::Exception::TypeError(
          v8::String::New("One argument is required")));
  }
  return v8::Undefined();
}

v8::Handle<v8::Value> TypedArray::SubArray(
    const v8::Arguments& arguments) {
  TypedArray* self = static_cast<TypedArray*>(
      arguments.This()->GetPointerFromInternalField(0));
  int32_t end = self->GetByteLength();
  switch (arguments.Length()) {
  case 2:
    if (arguments[1]->IsInt32()) {
      end = arguments[1]->ToUint32()->Value();
      if (0 > end) {
        end = self->GetLength() + end;
        if (0 > end) {
          end = 0;
        }
      } else {
        if (static_cast<uint32_t>(end) > self->GetLength()) {
          end = self->GetLength() + 1;
        }
      }
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument two must be a long")));
    }
    // Fall through
  case 1:
    if (arguments[0]->IsInt32()) {
      int32_t start =
        arguments[0]->ToInt32()->Value();
      if (0 > start) {
        start = self->GetLength() + start;
        if (0 > start) {
          start = 0;
        }
      } else {
        if (static_cast<uint32_t>(start) > self->GetLength()) {
          start = self->GetLength() + 1;
        }
      }
      int32_t length = end - start - 1;
      if (0 > length) {
        length = 0;
      }
      v8::TryCatch try_catch;
      v8::Handle<v8::Value> argv[3] = {
        self->GetArrayBuffer(),
        v8::Uint32::New(start * self->BytesPerElement()),
        v8::Uint32::New(length)
      };
      v8::Handle<v8::Value> value = self->NewInstance(3, argv);
      if (value.IsEmpty()) {
        return try_catch.ReThrow();
      }
      return value;
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument one must be a long")));
    }
  default:
    return v8::ThrowException(v8::Exception::TypeError(
          v8::String::New("One or two arguments are required")));
  }
}

// Protected
v8::Handle<v8::Value> TypedArray::Construct(
    const v8::Arguments& arguments, v8::ExternalArrayType type) {
  uint32_t byte_offset = 0, length = 0;
  switch (arguments.Length()) {
  case 3:
    if (arguments[2]->IsUint32()) {
      length = arguments[2]->ToUint32()->Value();
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument three must be an unsigned long")));
    }
    // Fall through
  case 2:
    if (arguments[1]->IsUint32()) {
      byte_offset = arguments[1]->ToUint32()->Value();
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument two must be an unsigned long")));
    }
    if (arguments[0]->IsObject()) {
      if (!ArrayBuffer::GetTemplate()->HasInstance(arguments[0]->ToObject())) {
        return v8::ThrowException(v8::Exception::TypeError(
              v8::String::New("Argument one must be an ArrayBuffer")));
      }
    } else {
        return v8::ThrowException(v8::Exception::TypeError(
              v8::String::New("Argument one must be an object")));
    }
    // Fall through
  case 1:
    if (arguments[0]->IsUint32()) {
      // TypedArray(unsigned long length)
      uint32_t byte_length =
        arguments[0]->ToUint32()->Value() * BytesPerElement();
      v8::Handle<v8::Value> array_buffer = ArrayBuffer::New(byte_length);
      if (array_buffer->IsUndefined()) {
        return array_buffer;
      }
      v8::Handle<v8::Value> value =
        ArrayBufferView::Construct(array_buffer->ToObject(), 0, byte_length);
      if (value->IsUndefined()) {
        return value;
      }
      length_ = GetByteLength() / BytesPerElement();
      arguments.This()->SetIndexedPropertiesToExternalArrayData(GetBuffer(),
          type, GetLength());
    } else if (arguments[0]->IsArray()) {
      // TypedArray(type[] array)
      v8::Array* array = v8::Array::Cast(*arguments[0]);
      uint32_t byte_length = array->Length() * BytesPerElement();
      v8::Handle<v8::Value> array_buffer = ArrayBuffer::New(byte_length);
      if (array_buffer->IsUndefined()) {
        return array_buffer;
      }
      v8::Handle<v8::Value> value =
        ArrayBufferView::Construct(array_buffer->ToObject(), 0, byte_length);
      if (value->IsUndefined()) {
        return value;
      }
      length_ = GetByteLength() / BytesPerElement();
      arguments.This()->SetIndexedPropertiesToExternalArrayData(GetBuffer(),
          type, GetLength());
      for (uint32_t index = 0; index < array->Length(); ++index) {
        arguments.This()->Set(index, array->Get(index));
      }
    } else if (arguments[0]->IsObject()) {
      v8::Handle<v8::Object> object = arguments[0]->ToObject();
      if (GetTemplate()->HasInstance(object)) {
        // TypedArray(TypedArray array)
        TypedArray* that = static_cast<TypedArray*>(
            object->GetPointerFromInternalField(0));
        v8::Handle<v8::Value> array_buffer =
          ArrayBuffer::New(that->GetByteLength());
        if (array_buffer->IsUndefined()) {
          return array_buffer;
        }
        v8::Handle<v8::Value> value = ArrayBufferView::Construct(
            array_buffer->ToObject(), 0, that->GetByteLength());
        length_ = GetByteLength() / BytesPerElement();
        if (value->IsUndefined()) {
          return value;
        }
        ::memcpy(GetBuffer(), that->GetBuffer(), that->GetByteLength());
        arguments.This()->SetIndexedPropertiesToExternalArrayData(GetBuffer(),
            type, GetLength());
      } else if (ArrayBuffer::GetTemplate()->HasInstance(object)) {
        // TypedArray(ArrayBuffer buffer,
        //            optional unsigned long byteOffset,
        //            option unsigned long length)
        moka::ArrayBuffer* buffer = static_cast<moka::ArrayBuffer*>(
            object->GetPointerFromInternalField(0));
        uint32_t byte_length;
        if (arguments.Length() == 3) {
          byte_length = length * BytesPerElement();
        } else {
          byte_length = buffer->GetByteLength() - byte_offset;
        }
        if (byte_offset >= buffer->GetByteLength()) {
          return v8::ThrowException(v8::Exception::RangeError(
                v8::String::New("Offset is out of range")));
        }
        if (byte_offset + byte_length > buffer->GetByteLength()) {
          return v8::ThrowException(v8::Exception::RangeError(
                v8::String::New("Length is out of range")));
        }
        if (byte_length % BytesPerElement()) {
          std::stringstream message;
          message << "Length minus offset must be a multiple of ";
          message << BytesPerElement();
          return v8::ThrowException(v8::Exception::RangeError(
                v8::String::New(message.str().c_str())));
        }
        v8::Handle<v8::Value> value =
          ArrayBufferView::Construct(object, byte_offset, byte_length);
        if (value->IsUndefined()) {
          return value;
        }
        length_ = GetByteLength() / BytesPerElement();
        arguments.This()->SetIndexedPropertiesToExternalArrayData(
            static_cast<int8_t*>(GetBuffer()) + byte_offset, type, GetLength());
      } else {
        return v8::ThrowException(v8::Exception::TypeError(
              v8::String::New("Argument one must be an ArrayBuffer"
                " or a TypedArray")));
      }
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument one must be an unsigned long,"
              " and array or an object")));
    }
    break;
  default:
    return v8::ThrowException(v8::Exception::TypeError(
          v8::String::New("One, two or three arguments required")));
  }
  return v8::True();
}

} // namespace moka

// vim: tabstop=2:sw=2:expandtab
<commit_msg>Updated the 'set' method for ArrayBufferView<commit_after>// Copyright 2011 Michael Steinert. All rights reserved.
// 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.
//     * The names of the copyright holder, the author, nor any 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.

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <cerrno>
#include <cstdlib>
#include <cstring>
#include "moka/typed-array.h"
#include "moka/module.h"
#include <sstream>

namespace moka {

TypedArray::TypedArray()
  : length_(0) {}

// Public interface
v8::Handle<v8::FunctionTemplate> TypedArray::GetTemplate() {
  static v8::Persistent<v8::FunctionTemplate> templ_;
  if (!templ_.IsEmpty()) {
    return templ_;
  }
  v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
  templ->SetClassName(v8::String::NewSymbol("TypedArray"));
  templ->Inherit(ArrayBufferView::GetTemplate());
  // Properties
  templ->PrototypeTemplate()->SetAccessor(v8::String::NewSymbol("length"),
      Length);
  // Methods
  templ->PrototypeTemplate()->Set(v8::String::NewSymbol("get"),
      v8::FunctionTemplate::New(Get)->GetFunction());
  templ->PrototypeTemplate()->Set(v8::String::NewSymbol("set"),
      v8::FunctionTemplate::New(Set)->GetFunction());
  templ->PrototypeTemplate()->Set(v8::String::NewSymbol("subarray"),
      v8::FunctionTemplate::New(SubArray)->GetFunction());
  templ_ = v8::Persistent<v8::FunctionTemplate>::New(templ);
  return templ_;
}

// Private V8 interface
v8::Handle<v8::Value> TypedArray::Length(v8::Local<v8::String> property,
    const v8::AccessorInfo &info) {
  return v8::Uint32::New(static_cast<TypedArray*>(
        info.This()->GetPointerFromInternalField(0))->GetLength());
}

v8::Handle<v8::Value> TypedArray::Get(const v8::Arguments& arguments) {
  switch (arguments.Length()) {
  case 1:
    if (arguments[0]->IsUint32()) {
      TypedArray* self = static_cast<TypedArray*>(
          arguments.This()->GetPointerFromInternalField(0));
      uint32_t index = arguments[0]->ToUint32()->Value();
      if (index < self->GetLength()) {
        return arguments.This()->Get(index);
      }
      return v8::Undefined();
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument one must be an unsigned long")));
    }
  default:
    return v8::ThrowException(v8::Exception::TypeError(
          v8::String::New("One argument is required")));
  }
}

v8::Handle<v8::Value> TypedArray::Set(const v8::Arguments& arguments) {
  TypedArray* self = static_cast<TypedArray*>(
      arguments.This()->GetPointerFromInternalField(0));
  uint32_t offset = 0;
  switch (arguments.Length()) {
  case 2:
    if (arguments[0]->IsUint32()) {
      uint32_t index = arguments[0]->ToUint32()->Value();
      if (index < self->GetLength()) {
        arguments.This()->Set(index, arguments[1]);
      }
      return v8::Undefined();
    } else {
      if (arguments[1]->IsUint32()) {
        offset = arguments[1]->ToUint32()->Value();
      } else {
        return v8::ThrowException(v8::Exception::TypeError(
              v8::String::New("Argument two must be an unsigned long")));
      }
    }
    // Fall through
  case 1:
    if (arguments[0]->IsObject()) {
      v8::Handle<v8::Object> object = arguments[0]->ToObject();
      if (object->IsArray()) {
        v8::Array* array = v8::Array::Cast(*arguments[0]);
        if (offset + array->Length() > self->GetLength()) {
          return v8::ThrowException(v8::Exception::RangeError(
                v8::String::New("Offset is out of range")));
        }
        for (uint32_t index = 0; index < self->GetLength(); ++index) {
          arguments.This()->Set(index + offset, array->Get(index));
        }
      } else if (GetTemplate()->HasInstance(object)) {
        TypedArray* that = static_cast<TypedArray*>(
            object->GetPointerFromInternalField(0));
        if (offset + that->GetLength() > self->GetLength()) {
          return v8::ThrowException(v8::Exception::RangeError(
                v8::String::New("Offset is out of range")));
        }
        if (self->GetBuffer() == that->GetBuffer()
            && self->GetByteOffset() + self->GetByteLength()
            > that->GetByteOffset()) {
          int8_t* buffer = static_cast<int8_t*>(
              ::malloc(self->GetByteLength()));
          if (!buffer) {
            return v8::ThrowException(Module::ErrnoException::New(errno));
          }
          ::memcpy(buffer, that->GetBuffer(), that->GetByteLength());
          ::memcpy(static_cast<int8_t*>(self->GetBuffer()) + offset,
              buffer, that->GetByteLength());
          ::free(buffer);
        } else {
          ::memcpy(static_cast<int8_t*>(self->GetBuffer()) + offset,
              that->GetBuffer(), that->GetByteLength());
        }
      } else {
        return v8::ThrowException(v8::Exception::TypeError(
              v8::String::New("Argument one must be an array")));
      }
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument one must be an object")));
    }
    break;
  default:
    return v8::ThrowException(v8::Exception::TypeError(
          v8::String::New("One argument is required")));
  }
  return v8::Undefined();
}

v8::Handle<v8::Value> TypedArray::SubArray(
    const v8::Arguments& arguments) {
  TypedArray* self = static_cast<TypedArray*>(
      arguments.This()->GetPointerFromInternalField(0));
  int32_t end = self->GetByteLength();
  switch (arguments.Length()) {
  case 2:
    if (arguments[1]->IsInt32()) {
      end = arguments[1]->ToUint32()->Value();
      if (0 > end) {
        end = self->GetLength() + end;
        if (0 > end) {
          end = 0;
        }
      } else {
        if (static_cast<uint32_t>(end) > self->GetLength()) {
          end = self->GetLength() + 1;
        }
      }
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument two must be a long")));
    }
    // Fall through
  case 1:
    if (arguments[0]->IsInt32()) {
      int32_t start =
        arguments[0]->ToInt32()->Value();
      if (0 > start) {
        start = self->GetLength() + start;
        if (0 > start) {
          start = 0;
        }
      } else {
        if (static_cast<uint32_t>(start) > self->GetLength()) {
          start = self->GetLength() + 1;
        }
      }
      int32_t length = end - start - 1;
      if (0 > length) {
        length = 0;
      }
      v8::TryCatch try_catch;
      v8::Handle<v8::Value> argv[3] = {
        self->GetArrayBuffer(),
        v8::Uint32::New(start * self->BytesPerElement()),
        v8::Uint32::New(length)
      };
      v8::Handle<v8::Value> value = self->NewInstance(3, argv);
      if (value.IsEmpty()) {
        return try_catch.ReThrow();
      }
      return value;
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument one must be a long")));
    }
  default:
    return v8::ThrowException(v8::Exception::TypeError(
          v8::String::New("One or two arguments are required")));
  }
}

// Protected
v8::Handle<v8::Value> TypedArray::Construct(
    const v8::Arguments& arguments, v8::ExternalArrayType type) {
  uint32_t byte_offset = 0, length = 0;
  switch (arguments.Length()) {
  case 3:
    if (arguments[2]->IsUint32()) {
      length = arguments[2]->ToUint32()->Value();
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument three must be an unsigned long")));
    }
    // Fall through
  case 2:
    if (arguments[1]->IsUint32()) {
      byte_offset = arguments[1]->ToUint32()->Value();
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument two must be an unsigned long")));
    }
    if (arguments[0]->IsObject()) {
      if (!ArrayBuffer::GetTemplate()->HasInstance(arguments[0]->ToObject())) {
        return v8::ThrowException(v8::Exception::TypeError(
              v8::String::New("Argument one must be an ArrayBuffer")));
      }
    } else {
        return v8::ThrowException(v8::Exception::TypeError(
              v8::String::New("Argument one must be an object")));
    }
    // Fall through
  case 1:
    if (arguments[0]->IsUint32()) {
      // TypedArray(unsigned long length)
      uint32_t byte_length =
        arguments[0]->ToUint32()->Value() * BytesPerElement();
      v8::Handle<v8::Value> array_buffer = ArrayBuffer::New(byte_length);
      if (array_buffer->IsUndefined()) {
        return array_buffer;
      }
      v8::Handle<v8::Value> value =
        ArrayBufferView::Construct(array_buffer->ToObject(), 0, byte_length);
      if (value->IsUndefined()) {
        return value;
      }
      length_ = GetByteLength() / BytesPerElement();
      arguments.This()->SetIndexedPropertiesToExternalArrayData(GetBuffer(),
          type, GetLength());
    } else if (arguments[0]->IsArray()) {
      // TypedArray(type[] array)
      v8::Array* array = v8::Array::Cast(*arguments[0]);
      uint32_t byte_length = array->Length() * BytesPerElement();
      v8::Handle<v8::Value> array_buffer = ArrayBuffer::New(byte_length);
      if (array_buffer->IsUndefined()) {
        return array_buffer;
      }
      v8::Handle<v8::Value> value =
        ArrayBufferView::Construct(array_buffer->ToObject(), 0, byte_length);
      if (value->IsUndefined()) {
        return value;
      }
      length_ = GetByteLength() / BytesPerElement();
      arguments.This()->SetIndexedPropertiesToExternalArrayData(GetBuffer(),
          type, GetLength());
      for (uint32_t index = 0; index < array->Length(); ++index) {
        arguments.This()->Set(index, array->Get(index));
      }
    } else if (arguments[0]->IsObject()) {
      v8::Handle<v8::Object> object = arguments[0]->ToObject();
      if (GetTemplate()->HasInstance(object)) {
        // TypedArray(TypedArray array)
        TypedArray* that = static_cast<TypedArray*>(
            object->GetPointerFromInternalField(0));
        v8::Handle<v8::Value> array_buffer =
          ArrayBuffer::New(that->GetByteLength());
        if (array_buffer->IsUndefined()) {
          return array_buffer;
        }
        v8::Handle<v8::Value> value = ArrayBufferView::Construct(
            array_buffer->ToObject(), 0, that->GetByteLength());
        length_ = GetByteLength() / BytesPerElement();
        if (value->IsUndefined()) {
          return value;
        }
        ::memcpy(GetBuffer(), that->GetBuffer(), that->GetByteLength());
        arguments.This()->SetIndexedPropertiesToExternalArrayData(GetBuffer(),
            type, GetLength());
      } else if (ArrayBuffer::GetTemplate()->HasInstance(object)) {
        // TypedArray(ArrayBuffer buffer,
        //            optional unsigned long byteOffset,
        //            option unsigned long length)
        moka::ArrayBuffer* buffer = static_cast<moka::ArrayBuffer*>(
            object->GetPointerFromInternalField(0));
        uint32_t byte_length;
        if (arguments.Length() == 3) {
          byte_length = length * BytesPerElement();
        } else {
          byte_length = buffer->GetByteLength() - byte_offset;
        }
        if (byte_offset >= buffer->GetByteLength()) {
          return v8::ThrowException(v8::Exception::RangeError(
                v8::String::New("Offset is out of range")));
        }
        if (byte_offset + byte_length > buffer->GetByteLength()) {
          return v8::ThrowException(v8::Exception::RangeError(
                v8::String::New("Length is out of range")));
        }
        if (byte_length % BytesPerElement()) {
          std::stringstream message;
          message << "Length minus offset must be a multiple of ";
          message << BytesPerElement();
          return v8::ThrowException(v8::Exception::RangeError(
                v8::String::New(message.str().c_str())));
        }
        v8::Handle<v8::Value> value =
          ArrayBufferView::Construct(object, byte_offset, byte_length);
        if (value->IsUndefined()) {
          return value;
        }
        length_ = GetByteLength() / BytesPerElement();
        arguments.This()->SetIndexedPropertiesToExternalArrayData(
            static_cast<int8_t*>(GetBuffer()) + byte_offset, type, GetLength());
      } else {
        return v8::ThrowException(v8::Exception::TypeError(
              v8::String::New("Argument one must be an ArrayBuffer"
                " or a TypedArray")));
      }
    } else {
      return v8::ThrowException(v8::Exception::TypeError(
            v8::String::New("Argument one must be an unsigned long,"
              " and array or an object")));
    }
    break;
  default:
    return v8::ThrowException(v8::Exception::TypeError(
          v8::String::New("One, two or three arguments required")));
  }
  return v8::True();
}

} // namespace moka

// vim: tabstop=2:sw=2:expandtab
<|endoftext|>


<commit_before>// -*- C++ -*-
//
// ----------------------------------------------------------------------
//
//                           Brad T. Aagaard
//                        U.S. Geological Survey
//
// <LicenseText>
//
// ----------------------------------------------------------------------
//

/** @file libsrc/spatialdb/SimpleIOAscii.hh
 *
 * @brief C++ object for reading/writing SimpleDB info as ASCII files.
 */

#if !defined(spatialdata_spatialdb_simpleioascii_hh)
#define spatialdata_spatialdb_simpleioascii_hh

#include <iosfwd> // USES std::istream

namespace spatialdata {
  namespace spatialdb {
    class SimpleIOAscii;
    class SimpleIO;
  } // spatialdb
} // spatialdata

// ----------------------------------------------------------------------
class spatialdata::spatialdb::SimpleIOAscii : public SimpleIO
{ // SimpleIOAscii

public :
  // PUBLIC METHODS /////////////////////////////////////////////////////

  // Using default constructor.

  // Using default destructor.

  // Using default copy constructor

  /** Clone object.
   *
   * @returns Pointer copy of this.
   */
  SimpleIO* clone(void) const;

  /** Read the database.
   *
   * @param pData Database data
   * @param ppCS Pointer to coordinate system
   */
  void read(SimpleDB::DataStruct* pData,
	    spatialdata::geocoords::CoordSys** ppCS);

  /** Write the database.
   *
   * @param data Database data
   * @param pCS Pointer to coordinate system
   */
  void write(const SimpleDB::DataStruct& data,
	     const spatialdata::geocoords::CoordSys* pCS);

private :
  // PRIVATE METHODS ////////////////////////////////////////////////////

  /** Read database version 1 file.
   *
   * @param pData Database data
   * @param ppCS Pointer to coordinate system
   * @param filein File input stream
   */
  static void _readV1(SimpleDB::DataStruct* pData,
		      spatialdata::geocoords::CoordSys** ppCS,
		      std::istream& filein);

 private :
  // PRIVATE MEMBERS ////////////////////////////////////////////////////

  /** Magic header in ascii files */
  static const char* HEADER;

}; // class SimpleIOAscii

#include "SimpleIOAscii.icc" // inline methods

#endif // spatialdata_spatialdb_SimpleIOAscii_hh

// version
// $Id$

// End of file
<commit_msg>Added missing include directive in SimpleIOAscii (include parent).<commit_after>// -*- C++ -*-
//
// ----------------------------------------------------------------------
//
//                           Brad T. Aagaard
//                        U.S. Geological Survey
//
// <LicenseText>
//
// ----------------------------------------------------------------------
//

/** @file libsrc/spatialdb/SimpleIOAscii.hh
 *
 * @brief C++ object for reading/writing SimpleDB info as ASCII files.
 */

#if !defined(spatialdata_spatialdb_simpleioascii_hh)
#define spatialdata_spatialdb_simpleioascii_hh

#include "SimpleIO.hh"

#include <iosfwd> // USES std::istream

namespace spatialdata {
  namespace spatialdb {
    class SimpleIOAscii;
  } // spatialdb
} // spatialdata

// ----------------------------------------------------------------------
class spatialdata::spatialdb::SimpleIOAscii : public SimpleIO
{ // SimpleIOAscii

public :
  // PUBLIC METHODS /////////////////////////////////////////////////////

  // Using default constructor.

  // Using default destructor.

  // Using default copy constructor

  /** Clone object.
   *
   * @returns Pointer copy of this.
   */
  SimpleIO* clone(void) const;

  /** Read the database.
   *
   * @param pData Database data
   * @param ppCS Pointer to coordinate system
   */
  void read(SimpleDB::DataStruct* pData,
	    spatialdata::geocoords::CoordSys** ppCS);

  /** Write the database.
   *
   * @param data Database data
   * @param pCS Pointer to coordinate system
   */
  void write(const SimpleDB::DataStruct& data,
	     const spatialdata::geocoords::CoordSys* pCS);

private :
  // PRIVATE METHODS ////////////////////////////////////////////////////

  /** Read database version 1 file.
   *
   * @param pData Database data
   * @param ppCS Pointer to coordinate system
   * @param filein File input stream
   */
  static void _readV1(SimpleDB::DataStruct* pData,
		      spatialdata::geocoords::CoordSys** ppCS,
		      std::istream& filein);

 private :
  // PRIVATE MEMBERS ////////////////////////////////////////////////////

  /** Magic header in ascii files */
  static const char* HEADER;

}; // class SimpleIOAscii

#include "SimpleIOAscii.icc" // inline methods

#endif // spatialdata_spatialdb_SimpleIOAscii_hh

// version
// $Id$

// End of file
<|endoftext|>