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

#ifndef _STREAM_HXX //autogen
#include <tools/stream.hxx>
#endif

#include "sbx.hxx"
#include "sbxres.hxx"

TYPEINIT1(SbxCollection,SbxObject)
TYPEINIT1(SbxStdCollection,SbxCollection)

static const char* pCount;
static const char* pAdd;
static const char* pItem;
static const char* pRemove;
static USHORT nCountHash = 0, nAddHash, nItemHash, nRemoveHash;

/////////////////////////////////////////////////////////////////////////

SbxCollection::SbxCollection( const XubString& rClass )
             : SbxObject( rClass )
{
    if( !nCountHash )
    {
        pCount  = GetSbxRes( STRING_COUNTPROP );
        pAdd    = GetSbxRes( STRING_ADDMETH );
        pItem   = GetSbxRes( STRING_ITEMMETH );
        pRemove = GetSbxRes( STRING_REMOVEMETH );
        nCountHash  = MakeHashCode( String::CreateFromAscii( pCount ) );
        nAddHash    = MakeHashCode( String::CreateFromAscii( pAdd ) );
        nItemHash   = MakeHashCode( String::CreateFromAscii( pItem ) );
        nRemoveHash = MakeHashCode( String::CreateFromAscii( pRemove ) );
    }
    Initialize();
    // Fuer Zugriffe auf sich selbst
    StartListening( GetBroadcaster(), TRUE );
}

SbxCollection::SbxCollection( const SbxCollection& rColl )
             : SbxObject( rColl )
{}

SbxCollection& SbxCollection::operator=( const SbxCollection& r )
{
    if( &r != this )
        SbxObject::operator=( r );
    return *this;
}

SbxCollection::~SbxCollection()
{}

void SbxCollection::Clear()
{
    SbxObject::Clear();
    Initialize();
}

void SbxCollection::Initialize()
{
    SetType( SbxOBJECT );
    SetFlag( SBX_FIXED );
    ResetFlag( SBX_WRITE );
    SbxVariable* p;
    p = Make( String::CreateFromAscii( pCount ), SbxCLASS_PROPERTY, SbxINTEGER );
    p->ResetFlag( SBX_WRITE );
    p->SetFlag( SBX_DONTSTORE );
    p = Make( String::CreateFromAscii( pAdd ), SbxCLASS_METHOD, SbxEMPTY );
    p->SetFlag( SBX_DONTSTORE );
    p = Make( String::CreateFromAscii( pItem ), SbxCLASS_METHOD, SbxOBJECT );
    p->SetFlag( SBX_DONTSTORE );
    p = Make( String::CreateFromAscii( pRemove ), SbxCLASS_METHOD, SbxEMPTY );
    p->SetFlag( SBX_DONTSTORE );
}

SbxVariable* SbxCollection::FindUserData( UINT32 nData )
{
    if( GetParameters() )
    {
        SbxObject* pObj = (SbxObject*) GetObject();
        return pObj ? pObj->FindUserData( nData ) : NULL;
    }
    else
        return SbxObject::FindUserData( nData );
}

SbxVariable* SbxCollection::Find( const XubString& rName, SbxClassType t )
{
    if( GetParameters() )
    {
        SbxObject* pObj = (SbxObject*) GetObject();
        return pObj ? pObj->Find( rName, t ) : NULL;
    }
    else
        return SbxObject::Find( rName, t );
}

void SbxCollection::SFX_NOTIFY( SfxBroadcaster& rCst, const TypeId& rId1,
                                const SfxHint& rHint, const TypeId& rId2 )
{
    const SbxHint* p = PTR_CAST(SbxHint,&rHint);
    if( p )
    {
        ULONG nId = p->GetId();
        BOOL bRead  = BOOL( nId == SBX_HINT_DATAWANTED );
        BOOL bWrite = BOOL( nId == SBX_HINT_DATACHANGED );
        SbxVariable* pVar = p->GetVar();
        SbxArray* pArg = pVar->GetParameters();
        if( bRead || bWrite )
        {
            XubString aVarName( pVar->GetName() );
            if( pVar == this )
                CollItem( pArg );
            else if( pVar->GetHashCode() == nCountHash
                  && aVarName.EqualsIgnoreCaseAscii( pCount ) )
                pVar->PutLong( pObjs->Count() );
            else if( pVar->GetHashCode() == nAddHash
                  && aVarName.EqualsIgnoreCaseAscii( pAdd ) )
                CollAdd( pArg );
            else if( pVar->GetHashCode() == nItemHash
                  && aVarName.EqualsIgnoreCaseAscii( pItem ) )
                CollItem( pArg );
            else if( pVar->GetHashCode() == nRemoveHash
                  && aVarName.EqualsIgnoreCaseAscii( pRemove ) )
                CollRemove( pArg );
            else
                SbxObject::SFX_NOTIFY( rCst, rId1, rHint, rId2 );
            return;
        }
    }
    SbxObject::SFX_NOTIFY( rCst, rId1, rHint, rId2 );
}

// Default: Argument ist Objekt

void SbxCollection::CollAdd( SbxArray* pPar )
{
    if( pPar->Count() != 2 )
        SetError( SbxERR_WRONG_ARGS );
    else
    {
        SbxBase* pObj = pPar->Get( 1 )->GetObject();
        if( !pObj || !( pObj->ISA(SbxObject) ) )
            SetError( SbxERR_NOTIMP );
        else
            Insert( (SbxObject*) pObj );
    }
}

// Default: Index ab 1 oder der Objektname

void SbxCollection::CollItem( SbxArray* pPar )
{
    if( pPar->Count() != 2 )
        SetError( SbxERR_WRONG_ARGS );
    else
    {
        SbxVariable* pRes = NULL;
        SbxVariable* p = pPar->Get( 1 );
        if( p->GetType() == SbxSTRING )
            pRes = Find( p->GetString(), SbxCLASS_OBJECT );
        else
        {
            short n = p->GetInteger();
            if( n >= 1 && n <= (short) pObjs->Count() )
                pRes = pObjs->Get( (USHORT) n - 1 );
        }
        if( !pRes )
            SetError( SbxERR_BAD_INDEX );
        pPar->Get( 0 )->PutObject( pRes );
    }
}

// Default: Index ab 1

void SbxCollection::CollRemove( SbxArray* pPar )
{
    if( pPar->Count() != 2 )
        SetError( SbxERR_WRONG_ARGS );
    else
    {
        short n = pPar->Get( 1 )->GetInteger();
        if( n < 1 || n > (short) pObjs->Count() )
            SetError( SbxERR_BAD_INDEX );
        else
            Remove( pObjs->Get( (USHORT) n - 1 ) );
    }
}

BOOL SbxCollection::LoadData( SvStream& rStrm, USHORT nVer )
{
    BOOL bRes = SbxObject::LoadData( rStrm, nVer );
    Initialize();
    return bRes;
}

/////////////////////////////////////////////////////////////////////////

SbxStdCollection::SbxStdCollection
                    ( const XubString& rClass, const XubString& rElem, BOOL b )
                  : SbxCollection( rClass ), aElemClass( rElem ),
                    bAddRemoveOk( b )
{}

SbxStdCollection::SbxStdCollection( const SbxStdCollection& r )
                  : SbxCollection( r ), aElemClass( r.aElemClass ),
                    bAddRemoveOk( r.bAddRemoveOk )
{}

SbxStdCollection& SbxStdCollection::operator=( const SbxStdCollection& r )
{
    if( &r != this )
    {
        if( !r.aElemClass.EqualsIgnoreCaseAscii( aElemClass ) )
            SetError( SbxERR_CONVERSION );
        else
            SbxCollection::operator=( r );
    }
    return *this;
}

SbxStdCollection::~SbxStdCollection()
{}

// Default: Fehler, wenn falsches Objekt

void SbxStdCollection::Insert( SbxVariable* p )
{
    SbxObject* pObj = PTR_CAST(SbxObject,p);
    if( pObj && !pObj->IsClass( aElemClass ) )
        SetError( SbxERR_BAD_ACTION );
    else
        SbxCollection::Insert( p );
}

void SbxStdCollection::CollAdd( SbxArray* pPar )
{
    if( !bAddRemoveOk )
        SetError( SbxERR_BAD_ACTION );
    else
        SbxCollection::CollAdd( pPar );
}

void SbxStdCollection::CollRemove( SbxArray* pPar )
{
    if( !bAddRemoveOk )
        SetError( SbxERR_BAD_ACTION );
    else
        SbxCollection::CollRemove( pPar );
}

BOOL SbxStdCollection::LoadData( SvStream& rStrm, USHORT nVer )
{
    BOOL bRes = SbxCollection::LoadData( rStrm, nVer );
    if( bRes )
    {
        rStrm.ReadByteString( aElemClass, RTL_TEXTENCODING_ASCII_US );
        rStrm >> bAddRemoveOk;
    }
    return bRes;
}

BOOL SbxStdCollection::StoreData( SvStream& rStrm ) const
{
    BOOL bRes = SbxCollection::StoreData( rStrm );
    if( bRes )
    {
        rStrm.WriteByteString( aElemClass, RTL_TEXTENCODING_ASCII_US );
        rStrm << bAddRemoveOk;
    }
    return bRes;
}

<commit_msg>INTEGRATION: CWS warnings01 (1.3.28); FILE MERGED 2005/12/01 14:56:17 ab 1.3.28.1: #i53898# Removed warnings for unxlngi6<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: sbxcoll.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 17:49:38 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _STREAM_HXX //autogen
#include <tools/stream.hxx>
#endif

#include "sbx.hxx"
#include "sbxres.hxx"

TYPEINIT1(SbxCollection,SbxObject)
TYPEINIT1(SbxStdCollection,SbxCollection)

static const char* pCount;
static const char* pAdd;
static const char* pItem;
static const char* pRemove;
static USHORT nCountHash = 0, nAddHash, nItemHash, nRemoveHash;

/////////////////////////////////////////////////////////////////////////

SbxCollection::SbxCollection( const XubString& rClass )
             : SbxObject( rClass )
{
    if( !nCountHash )
    {
        pCount  = GetSbxRes( STRING_COUNTPROP );
        pAdd    = GetSbxRes( STRING_ADDMETH );
        pItem   = GetSbxRes( STRING_ITEMMETH );
        pRemove = GetSbxRes( STRING_REMOVEMETH );
        nCountHash  = MakeHashCode( String::CreateFromAscii( pCount ) );
        nAddHash    = MakeHashCode( String::CreateFromAscii( pAdd ) );
        nItemHash   = MakeHashCode( String::CreateFromAscii( pItem ) );
        nRemoveHash = MakeHashCode( String::CreateFromAscii( pRemove ) );
    }
    Initialize();
    // Fuer Zugriffe auf sich selbst
    StartListening( GetBroadcaster(), TRUE );
}

SbxCollection::SbxCollection( const SbxCollection& rColl )
    : SvRefBase( rColl ), SbxObject( rColl )
{}

SbxCollection& SbxCollection::operator=( const SbxCollection& r )
{
    if( &r != this )
        SbxObject::operator=( r );
    return *this;
}

SbxCollection::~SbxCollection()
{}

void SbxCollection::Clear()
{
    SbxObject::Clear();
    Initialize();
}

void SbxCollection::Initialize()
{
    SetType( SbxOBJECT );
    SetFlag( SBX_FIXED );
    ResetFlag( SBX_WRITE );
    SbxVariable* p;
    p = Make( String::CreateFromAscii( pCount ), SbxCLASS_PROPERTY, SbxINTEGER );
    p->ResetFlag( SBX_WRITE );
    p->SetFlag( SBX_DONTSTORE );
    p = Make( String::CreateFromAscii( pAdd ), SbxCLASS_METHOD, SbxEMPTY );
    p->SetFlag( SBX_DONTSTORE );
    p = Make( String::CreateFromAscii( pItem ), SbxCLASS_METHOD, SbxOBJECT );
    p->SetFlag( SBX_DONTSTORE );
    p = Make( String::CreateFromAscii( pRemove ), SbxCLASS_METHOD, SbxEMPTY );
    p->SetFlag( SBX_DONTSTORE );
}

SbxVariable* SbxCollection::FindUserData( UINT32 nData )
{
    if( GetParameters() )
    {
        SbxObject* pObj = (SbxObject*) GetObject();
        return pObj ? pObj->FindUserData( nData ) : NULL;
    }
    else
        return SbxObject::FindUserData( nData );
}

SbxVariable* SbxCollection::Find( const XubString& rName, SbxClassType t )
{
    if( GetParameters() )
    {
        SbxObject* pObj = (SbxObject*) GetObject();
        return pObj ? pObj->Find( rName, t ) : NULL;
    }
    else
        return SbxObject::Find( rName, t );
}

void SbxCollection::SFX_NOTIFY( SfxBroadcaster& rCst, const TypeId& rId1,
                                const SfxHint& rHint, const TypeId& rId2 )
{
    const SbxHint* p = PTR_CAST(SbxHint,&rHint);
    if( p )
    {
        ULONG nId = p->GetId();
        BOOL bRead  = BOOL( nId == SBX_HINT_DATAWANTED );
        BOOL bWrite = BOOL( nId == SBX_HINT_DATACHANGED );
        SbxVariable* pVar = p->GetVar();
        SbxArray* pArg = pVar->GetParameters();
        if( bRead || bWrite )
        {
            XubString aVarName( pVar->GetName() );
            if( pVar == this )
                CollItem( pArg );
            else if( pVar->GetHashCode() == nCountHash
                  && aVarName.EqualsIgnoreCaseAscii( pCount ) )
                pVar->PutLong( pObjs->Count() );
            else if( pVar->GetHashCode() == nAddHash
                  && aVarName.EqualsIgnoreCaseAscii( pAdd ) )
                CollAdd( pArg );
            else if( pVar->GetHashCode() == nItemHash
                  && aVarName.EqualsIgnoreCaseAscii( pItem ) )
                CollItem( pArg );
            else if( pVar->GetHashCode() == nRemoveHash
                  && aVarName.EqualsIgnoreCaseAscii( pRemove ) )
                CollRemove( pArg );
            else
                SbxObject::SFX_NOTIFY( rCst, rId1, rHint, rId2 );
            return;
        }
    }
    SbxObject::SFX_NOTIFY( rCst, rId1, rHint, rId2 );
}

// Default: Argument ist Objekt

void SbxCollection::CollAdd( SbxArray* pPar_ )
{
    if( pPar_->Count() != 2 )
        SetError( SbxERR_WRONG_ARGS );
    else
    {
        SbxBase* pObj = pPar_->Get( 1 )->GetObject();
        if( !pObj || !( pObj->ISA(SbxObject) ) )
            SetError( SbxERR_NOTIMP );
        else
            Insert( (SbxObject*) pObj );
    }
}

// Default: Index ab 1 oder der Objektname

void SbxCollection::CollItem( SbxArray* pPar_ )
{
    if( pPar_->Count() != 2 )
        SetError( SbxERR_WRONG_ARGS );
    else
    {
        SbxVariable* pRes = NULL;
        SbxVariable* p = pPar_->Get( 1 );
        if( p->GetType() == SbxSTRING )
            pRes = Find( p->GetString(), SbxCLASS_OBJECT );
        else
        {
            short n = p->GetInteger();
            if( n >= 1 && n <= (short) pObjs->Count() )
                pRes = pObjs->Get( (USHORT) n - 1 );
        }
        if( !pRes )
            SetError( SbxERR_BAD_INDEX );
        pPar_->Get( 0 )->PutObject( pRes );
    }
}

// Default: Index ab 1

void SbxCollection::CollRemove( SbxArray* pPar_ )
{
    if( pPar_->Count() != 2 )
        SetError( SbxERR_WRONG_ARGS );
    else
    {
        short n = pPar_->Get( 1 )->GetInteger();
        if( n < 1 || n > (short) pObjs->Count() )
            SetError( SbxERR_BAD_INDEX );
        else
            Remove( pObjs->Get( (USHORT) n - 1 ) );
    }
}

BOOL SbxCollection::LoadData( SvStream& rStrm, USHORT nVer )
{
    BOOL bRes = SbxObject::LoadData( rStrm, nVer );
    Initialize();
    return bRes;
}

/////////////////////////////////////////////////////////////////////////

SbxStdCollection::SbxStdCollection
                    ( const XubString& rClass, const XubString& rElem, BOOL b )
                  : SbxCollection( rClass ), aElemClass( rElem ),
                    bAddRemoveOk( b )
{}

SbxStdCollection::SbxStdCollection( const SbxStdCollection& r )
                  : SvRefBase( r ), SbxCollection( r ),
                    aElemClass( r.aElemClass ), bAddRemoveOk( r.bAddRemoveOk )
{}

SbxStdCollection& SbxStdCollection::operator=( const SbxStdCollection& r )
{
    if( &r != this )
    {
        if( !r.aElemClass.EqualsIgnoreCaseAscii( aElemClass ) )
            SetError( SbxERR_CONVERSION );
        else
            SbxCollection::operator=( r );
    }
    return *this;
}

SbxStdCollection::~SbxStdCollection()
{}

// Default: Fehler, wenn falsches Objekt

void SbxStdCollection::Insert( SbxVariable* p )
{
    SbxObject* pObj = PTR_CAST(SbxObject,p);
    if( pObj && !pObj->IsClass( aElemClass ) )
        SetError( SbxERR_BAD_ACTION );
    else
        SbxCollection::Insert( p );
}

void SbxStdCollection::CollAdd( SbxArray* pPar_ )
{
    if( !bAddRemoveOk )
        SetError( SbxERR_BAD_ACTION );
    else
        SbxCollection::CollAdd( pPar_ );
}

void SbxStdCollection::CollRemove( SbxArray* pPar_ )
{
    if( !bAddRemoveOk )
        SetError( SbxERR_BAD_ACTION );
    else
        SbxCollection::CollRemove( pPar_ );
}

BOOL SbxStdCollection::LoadData( SvStream& rStrm, USHORT nVer )
{
    BOOL bRes = SbxCollection::LoadData( rStrm, nVer );
    if( bRes )
    {
        rStrm.ReadByteString( aElemClass, RTL_TEXTENCODING_ASCII_US );
        rStrm >> bAddRemoveOk;
    }
    return bRes;
}

BOOL SbxStdCollection::StoreData( SvStream& rStrm ) const
{
    BOOL bRes = SbxCollection::StoreData( rStrm );
    if( bRes )
    {
        rStrm.WriteByteString( aElemClass, RTL_TEXTENCODING_ASCII_US );
        rStrm << bAddRemoveOk;
    }
    return bRes;
}

<|endoftext|>


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

#include "base/platform_file.h"

#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>

#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "base/utf_string_conversions.h"

#if defined(OS_ANDROID)
#include "base/os_compat_android.h"
#endif

namespace base {

#if defined(OS_BSD) || (defined(OS_MACOSX) && \
    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
typedef struct stat stat_wrapper_t;
static int CallFstat(int fd, stat_wrapper_t *sb) {
  base::ThreadRestrictions::AssertIOAllowed();
  return fstat(fd, sb);
}
#else
typedef struct stat64 stat_wrapper_t;
static int CallFstat(int fd, stat_wrapper_t *sb) {
  base::ThreadRestrictions::AssertIOAllowed();
  return fstat64(fd, sb);
}
#endif

// TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
PlatformFile CreatePlatformFile(const FilePath& name, int flags,
                                bool* created, PlatformFileError* error_code) {
  base::ThreadRestrictions::AssertIOAllowed();

  int open_flags = 0;
  if (flags & PLATFORM_FILE_CREATE)
    open_flags = O_CREAT | O_EXCL;

  if (created)
    *created = false;

  if (flags & PLATFORM_FILE_CREATE_ALWAYS) {
    DCHECK(!open_flags);
    open_flags = O_CREAT | O_TRUNC;
  }

  if (flags & PLATFORM_FILE_OPEN_TRUNCATED) {
    DCHECK(!open_flags);
    DCHECK(flags & PLATFORM_FILE_WRITE);
    open_flags = O_TRUNC;
  }

  if (!open_flags && !(flags & PLATFORM_FILE_OPEN) &&
      !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
    NOTREACHED();
    errno = EOPNOTSUPP;
    if (error_code)
      *error_code = PLATFORM_FILE_ERROR_FAILED;
    return kInvalidPlatformFileValue;
  }

  if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) {
    open_flags |= O_RDWR;
  } else if (flags & PLATFORM_FILE_WRITE) {
    open_flags |= O_WRONLY;
  } else if (!(flags & PLATFORM_FILE_READ) &&
             !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) &&
             !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
    NOTREACHED();
  }

  COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);

  int mode = S_IRUSR | S_IWUSR;
#if defined(OS_CHROMEOS)
  mode |= S_IRGRP | S_IROTH;
#endif

  int descriptor =
      HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));

  if (flags & PLATFORM_FILE_OPEN_ALWAYS) {
    if (descriptor <= 0) {
      open_flags |= O_CREAT;
      if (flags & PLATFORM_FILE_EXCLUSIVE_READ ||
          flags & PLATFORM_FILE_EXCLUSIVE_WRITE) {
        open_flags |= O_EXCL;   // together with O_CREAT implies O_NOFOLLOW
      }
      descriptor = HANDLE_EINTR(
          open(name.value().c_str(), open_flags, mode));
      if (created && descriptor > 0)
        *created = true;
    }
  }

  if (created && (descriptor > 0) &&
      (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)))
    *created = true;

  if ((descriptor > 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) {
    unlink(name.value().c_str());
  }

  if (error_code) {
    if (descriptor >= 0)
      *error_code = PLATFORM_FILE_OK;
    else {
      switch (errno) {
        case EACCES:
        case EISDIR:
        case EROFS:
        case EPERM:
          *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED;
          break;
        case ETXTBSY:
          *error_code = PLATFORM_FILE_ERROR_IN_USE;
          break;
        case EEXIST:
          *error_code = PLATFORM_FILE_ERROR_EXISTS;
          break;
        case ENOENT:
          *error_code = PLATFORM_FILE_ERROR_NOT_FOUND;
          break;
        case EMFILE:
          *error_code = PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
          break;
        case ENOMEM:
          *error_code = PLATFORM_FILE_ERROR_NO_MEMORY;
          break;
        case ENOSPC:
          *error_code = PLATFORM_FILE_ERROR_NO_SPACE;
          break;
        case ENOTDIR:
          *error_code = PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
          break;
        default:
          *error_code = PLATFORM_FILE_ERROR_FAILED;
      }
    }
  }

  return descriptor;
}

bool ClosePlatformFile(PlatformFile file) {
  base::ThreadRestrictions::AssertIOAllowed();
  return !HANDLE_EINTR(close(file));
}

int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
  base::ThreadRestrictions::AssertIOAllowed();
  if (file < 0 || size < 0)
    return -1;

  int bytes_read = 0;
  int rv;
  do {
    rv = HANDLE_EINTR(pread(file, data + bytes_read,
                            size - bytes_read, offset + bytes_read));
    if (rv <= 0)
      break;

    bytes_read += rv;
  } while (bytes_read < size);

  return bytes_read ? bytes_read : rv;
}

int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset,
                                 char* data, int size) {
  base::ThreadRestrictions::AssertIOAllowed();
  if (file < 0)
    return -1;

  return HANDLE_EINTR(pread(file, data, size, offset));
}

int WritePlatformFile(PlatformFile file, int64 offset,
                      const char* data, int size) {
  base::ThreadRestrictions::AssertIOAllowed();
  if (file < 0 || size < 0)
    return -1;

  int bytes_written = 0;
  int rv;
  do {
    rv = HANDLE_EINTR(pwrite(file, data + bytes_written,
                             size - bytes_written, offset + bytes_written));
    if (rv <= 0)
      break;

    bytes_written += rv;
  } while (bytes_written < size);

  return bytes_written ? bytes_written : rv;
}

bool TruncatePlatformFile(PlatformFile file, int64 length) {
  base::ThreadRestrictions::AssertIOAllowed();
  return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length)));
}

bool FlushPlatformFile(PlatformFile file) {
  base::ThreadRestrictions::AssertIOAllowed();
  return !HANDLE_EINTR(fsync(file));
}

bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
                       const base::Time& last_modified_time) {
  base::ThreadRestrictions::AssertIOAllowed();
  if (file < 0)
    return false;

  timeval times[2];
  times[0] = last_access_time.ToTimeVal();
  times[1] = last_modified_time.ToTimeVal();
  return !futimes(file, times);
}

bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
  if (!info)
    return false;

  stat_wrapper_t file_info;
  if (CallFstat(file, &file_info))
    return false;

  info->is_directory = S_ISDIR(file_info.st_mode);
  info->is_symbolic_link = S_ISLNK(file_info.st_mode);
  info->size = file_info.st_size;
  info->last_modified = base::Time::FromTimeT(file_info.st_mtime);
  info->last_accessed = base::Time::FromTimeT(file_info.st_atime);
  info->creation_time = base::Time::FromTimeT(file_info.st_ctime);
  return true;
}

}  // namespace base
<commit_msg>[Coverity] Fix possible leak.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/platform_file.h"

#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>

#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "base/utf_string_conversions.h"

#if defined(OS_ANDROID)
#include "base/os_compat_android.h"
#endif

namespace base {

#if defined(OS_BSD) || (defined(OS_MACOSX) && \
    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
typedef struct stat stat_wrapper_t;
static int CallFstat(int fd, stat_wrapper_t *sb) {
  base::ThreadRestrictions::AssertIOAllowed();
  return fstat(fd, sb);
}
#else
typedef struct stat64 stat_wrapper_t;
static int CallFstat(int fd, stat_wrapper_t *sb) {
  base::ThreadRestrictions::AssertIOAllowed();
  return fstat64(fd, sb);
}
#endif

// TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
PlatformFile CreatePlatformFile(const FilePath& name, int flags,
                                bool* created, PlatformFileError* error_code) {
  base::ThreadRestrictions::AssertIOAllowed();

  int open_flags = 0;
  if (flags & PLATFORM_FILE_CREATE)
    open_flags = O_CREAT | O_EXCL;

  if (created)
    *created = false;

  if (flags & PLATFORM_FILE_CREATE_ALWAYS) {
    DCHECK(!open_flags);
    open_flags = O_CREAT | O_TRUNC;
  }

  if (flags & PLATFORM_FILE_OPEN_TRUNCATED) {
    DCHECK(!open_flags);
    DCHECK(flags & PLATFORM_FILE_WRITE);
    open_flags = O_TRUNC;
  }

  if (!open_flags && !(flags & PLATFORM_FILE_OPEN) &&
      !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
    NOTREACHED();
    errno = EOPNOTSUPP;
    if (error_code)
      *error_code = PLATFORM_FILE_ERROR_FAILED;
    return kInvalidPlatformFileValue;
  }

  if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) {
    open_flags |= O_RDWR;
  } else if (flags & PLATFORM_FILE_WRITE) {
    open_flags |= O_WRONLY;
  } else if (!(flags & PLATFORM_FILE_READ) &&
             !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) &&
             !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
    NOTREACHED();
  }

  COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);

  int mode = S_IRUSR | S_IWUSR;
#if defined(OS_CHROMEOS)
  mode |= S_IRGRP | S_IROTH;
#endif

  int descriptor =
      HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));

  if (flags & PLATFORM_FILE_OPEN_ALWAYS) {
    if (descriptor < 0) {
      open_flags |= O_CREAT;
      if (flags & PLATFORM_FILE_EXCLUSIVE_READ ||
          flags & PLATFORM_FILE_EXCLUSIVE_WRITE) {
        open_flags |= O_EXCL;   // together with O_CREAT implies O_NOFOLLOW
      }
      descriptor = HANDLE_EINTR(
          open(name.value().c_str(), open_flags, mode));
      if (created && descriptor >= 0)
        *created = true;
    }
  }

  if (created && (descriptor >= 0) &&
      (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)))
    *created = true;

  if ((descriptor >= 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) {
    unlink(name.value().c_str());
  }

  if (error_code) {
    if (descriptor >= 0)
      *error_code = PLATFORM_FILE_OK;
    else {
      switch (errno) {
        case EACCES:
        case EISDIR:
        case EROFS:
        case EPERM:
          *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED;
          break;
        case ETXTBSY:
          *error_code = PLATFORM_FILE_ERROR_IN_USE;
          break;
        case EEXIST:
          *error_code = PLATFORM_FILE_ERROR_EXISTS;
          break;
        case ENOENT:
          *error_code = PLATFORM_FILE_ERROR_NOT_FOUND;
          break;
        case EMFILE:
          *error_code = PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
          break;
        case ENOMEM:
          *error_code = PLATFORM_FILE_ERROR_NO_MEMORY;
          break;
        case ENOSPC:
          *error_code = PLATFORM_FILE_ERROR_NO_SPACE;
          break;
        case ENOTDIR:
          *error_code = PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
          break;
        default:
          *error_code = PLATFORM_FILE_ERROR_FAILED;
      }
    }
  }

  return descriptor;
}

bool ClosePlatformFile(PlatformFile file) {
  base::ThreadRestrictions::AssertIOAllowed();
  return !HANDLE_EINTR(close(file));
}

int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
  base::ThreadRestrictions::AssertIOAllowed();
  if (file < 0 || size < 0)
    return -1;

  int bytes_read = 0;
  int rv;
  do {
    rv = HANDLE_EINTR(pread(file, data + bytes_read,
                            size - bytes_read, offset + bytes_read));
    if (rv <= 0)
      break;

    bytes_read += rv;
  } while (bytes_read < size);

  return bytes_read ? bytes_read : rv;
}

int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset,
                                 char* data, int size) {
  base::ThreadRestrictions::AssertIOAllowed();
  if (file < 0)
    return -1;

  return HANDLE_EINTR(pread(file, data, size, offset));
}

int WritePlatformFile(PlatformFile file, int64 offset,
                      const char* data, int size) {
  base::ThreadRestrictions::AssertIOAllowed();
  if (file < 0 || size < 0)
    return -1;

  int bytes_written = 0;
  int rv;
  do {
    rv = HANDLE_EINTR(pwrite(file, data + bytes_written,
                             size - bytes_written, offset + bytes_written));
    if (rv <= 0)
      break;

    bytes_written += rv;
  } while (bytes_written < size);

  return bytes_written ? bytes_written : rv;
}

bool TruncatePlatformFile(PlatformFile file, int64 length) {
  base::ThreadRestrictions::AssertIOAllowed();
  return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length)));
}

bool FlushPlatformFile(PlatformFile file) {
  base::ThreadRestrictions::AssertIOAllowed();
  return !HANDLE_EINTR(fsync(file));
}

bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
                       const base::Time& last_modified_time) {
  base::ThreadRestrictions::AssertIOAllowed();
  if (file < 0)
    return false;

  timeval times[2];
  times[0] = last_access_time.ToTimeVal();
  times[1] = last_modified_time.ToTimeVal();
  return !futimes(file, times);
}

bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
  if (!info)
    return false;

  stat_wrapper_t file_info;
  if (CallFstat(file, &file_info))
    return false;

  info->is_directory = S_ISDIR(file_info.st_mode);
  info->is_symbolic_link = S_ISLNK(file_info.st_mode);
  info->size = file_info.st_size;
  info->last_modified = base::Time::FromTimeT(file_info.st_mtime);
  info->last_accessed = base::Time::FromTimeT(file_info.st_atime);
  info->creation_time = base::Time::FromTimeT(file_info.st_ctime);
  return true;
}

}  // namespace base
<|endoftext|>


<commit_before>#define WIN32_LEAN_AND_MEAN
#define STRICT
#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _CRTDBG_MAP_ALLOC
#include <windows.h>
#include <atlbase.h>
#include <atlfile.h>
#include <pathcch.h>
#include <shlwapi.h>
#include <winioctl.h>
#include <algorithm>
#include <clocale>
#include <cstdio>
#include <memory>
#include <crtdbg.h>
#pragma comment(lib, "pathcch")
#pragma comment(lib, "shlwapi")
#pragma comment(lib, "user32")

std::unique_ptr<WCHAR[]> GetWindowsError( ULONG error_code = GetLastError() )
{
	auto msg = std::make_unique<WCHAR[]>( USHRT_MAX );
	if( FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM, nullptr, error_code, 0, msg.get(), USHRT_MAX, nullptr ) )
	{
		return msg;
	}
	return nullptr;
}
void PrintWindowsError( ULONG error_code = GetLastError() )
{
	if( auto error_msg = GetWindowsError( error_code ) )
	{
		fprintf( stderr, "%ls\n", error_msg.get() );
	}
}
_Success_( return == true )
bool reflink( _In_z_ PCWSTR oldpath, _In_z_ PCWSTR newpath )
{
	_ASSERTE( oldpath != nullptr && newpath != nullptr );
	ATL::CAtlFile source{ CreateFileW( oldpath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr ) };
	if( source == INVALID_HANDLE_VALUE )
	{
		source.Detach();
		return false;
	}

	ULONG fs_flags;
	if( !GetVolumeInformationByHandleW( source, nullptr, 0, nullptr, nullptr, &fs_flags, nullptr, 0 ) )
	{
		return false;
	}
	if( !( fs_flags & FILE_SUPPORTS_BLOCK_REFCOUNTING ) )
	{
		SetLastError( ERROR_NOT_CAPABLE );
		return false;
	}

	FILE_STANDARD_INFO file_standard;
	if( !GetFileInformationByHandleEx( source, FileStandardInfo, &file_standard, sizeof file_standard ) )
	{
		return false;
	}
	FILE_BASIC_INFO file_basic;
	if( !GetFileInformationByHandleEx( source, FileBasicInfo, &file_basic, sizeof file_basic ) )
	{
		return false;
	}

#ifdef _DEBUG
	ATL::CAtlFile destination{ CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, 0, source ) };
#else
	ATL::CAtlFile destination{ CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, source ) };
#endif
	if( destination == INVALID_HANDLE_VALUE )
	{
		destination.Detach();
		return false;
	}
	FILE_DISPOSITION_INFO dispose = { TRUE };
	if( !SetFileInformationByHandle( destination, FileDispositionInfo, &dispose, sizeof dispose ) )
	{
		return false;
	}

	if( file_basic.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE )
	{
		ULONG dummy;
		if( !DeviceIoControl( destination, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &dummy, nullptr ) )
		{
			return false;
		}
	}
	FILE_END_OF_FILE_INFO end_of_file = { file_standard.EndOfFile };
	if( !SetFileInformationByHandle( destination, FileEndOfFileInfo, &end_of_file, sizeof end_of_file ) )
	{
		return false;
	}

	const unsigned split_threshold = 2U * 1024 * 1024 * 1024;
	auto mount_point = std::make_unique<WCHAR[]>( PATHCCH_MAX_CCH );
	if( !GetVolumePathNameW( oldpath, mount_point.get(), PATHCCH_MAX_CCH ) )
	{
		return false;
	}
	ULONG sectors_per_cluster, sector_size, junk;
	if( !GetDiskFreeSpaceW( mount_point.get(), &sectors_per_cluster, &sector_size, &junk, &junk ) )
	{
		return false;
	}
	ULONG cluster_size = sectors_per_cluster * sector_size;
	if( split_threshold % cluster_size != 0 )
	{
		SetLastError( ERROR_NOT_SUPPORTED );
		return false;
	}

	DUPLICATE_EXTENTS_DATA dup_extent = { source };
	for( LONG64 offset = 0, remain = file_standard.AllocationSize.QuadPart; remain > 0; offset += split_threshold, remain -= split_threshold )
	{
		dup_extent.SourceFileOffset.QuadPart = dup_extent.TargetFileOffset.QuadPart = offset;
		dup_extent.ByteCount.QuadPart = std::min<LONG64>( split_threshold, remain );
		_ASSERTE( dup_extent.ByteCount.HighPart == 0 );
		_RPT3( _CRT_WARN, "r=%llx\no=%llx\nb=%llx\n\n", remain, dup_extent.SourceFileOffset.QuadPart, dup_extent.ByteCount.QuadPart );
		ULONG dummy;
		if( !DeviceIoControl( destination, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &dup_extent, sizeof dup_extent, nullptr, 0, &dummy, nullptr ) )
		{
			_CrtDbgBreak();
			return false;
		}
	}

	FILETIME atime = { file_basic.LastAccessTime.LowPart, ULONG( file_basic.LastAccessTime.HighPart ) };
	FILETIME mtime = { file_basic.LastWriteTime.LowPart, ULONG( file_basic.LastWriteTime.HighPart ) };
	SetFileTime( destination, nullptr, &atime, &mtime );
	dispose.DeleteFile = FALSE;
	return SetFileInformationByHandle( destination, FileDispositionInfo, &dispose, sizeof dispose ) != 0;
}
int __cdecl wmain( int argc, PWSTR argv[] )
{
	_CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF );
	_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
	_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE );
	setlocale( LC_ALL, "" );

	if( argc != 3 )
	{
		fprintf(
			stderr,
			"Copy file without actual data write.\n"
			"\n"
			"%ls source destination\n"
			"\n"
			"source       Specifies a file to copy.\n"
			"             source must have placed on the ReFS volume.\n"
			"destination  Specifies new file name.\n"
			"             destination must have placed on the same volume as source.\n",
			PathFindFileNameW( argv[0] )
			);
		return EXIT_FAILURE;
	}
	auto source = std::make_unique<WCHAR[]>( PATHCCH_MAX_CCH );
	auto destination = std::make_unique<WCHAR[]>( PATHCCH_MAX_CCH );
	if( FAILED( PathCchCanonicalizeEx( source.get(), PATHCCH_MAX_CCH, argv[1], PATHCCH_ALLOW_LONG_PATHS ) )
		|| FAILED( PathCchCanonicalizeEx( destination.get(), PATHCCH_MAX_CCH, argv[2], PATHCCH_ALLOW_LONG_PATHS ) ) )
	{
		PrintWindowsError();
		return EXIT_FAILURE;
	}
	if( !reflink( source.get(), destination.get() ) )
	{
		PrintWindowsError();
		return EXIT_FAILURE;
	}
}<commit_msg>Retire CAtlFile<commit_after>#define WIN32_LEAN_AND_MEAN
#define STRICT
#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _CRTDBG_MAP_ALLOC
#include <windows.h>
#include <atlbase.h>
#include <pathcch.h>
#include <shlwapi.h>
#include <winioctl.h>
#include <algorithm>
#include <clocale>
#include <cstdio>
#include <memory>
#include <crtdbg.h>
#pragma comment(lib, "pathcch")
#pragma comment(lib, "shlwapi")
#pragma comment(lib, "user32")

std::unique_ptr<WCHAR[]> GetWindowsError( ULONG error_code = GetLastError() )
{
	auto msg = std::make_unique<WCHAR[]>( USHRT_MAX );
	if( FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM, nullptr, error_code, 0, msg.get(), USHRT_MAX, nullptr ) )
	{
		return msg;
	}
	return nullptr;
}
void PrintWindowsError( ULONG error_code = GetLastError() )
{
	if( auto error_msg = GetWindowsError( error_code ) )
	{
		fprintf( stderr, "%ls\n", error_msg.get() );
	}
}
_Success_( return == true )
bool reflink( _In_z_ PCWSTR oldpath, _In_z_ PCWSTR newpath )
{
	_ASSERTE( oldpath != nullptr && newpath != nullptr );
	ATL::CHandle source{ CreateFileW( oldpath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr ) };
	if( source == INVALID_HANDLE_VALUE )
	{
		source.Detach();
		return false;
	}

	ULONG fs_flags;
	if( !GetVolumeInformationByHandleW( source, nullptr, 0, nullptr, nullptr, &fs_flags, nullptr, 0 ) )
	{
		return false;
	}
	if( !( fs_flags & FILE_SUPPORTS_BLOCK_REFCOUNTING ) )
	{
		SetLastError( ERROR_NOT_CAPABLE );
		return false;
	}

	FILE_STANDARD_INFO file_standard;
	if( !GetFileInformationByHandleEx( source, FileStandardInfo, &file_standard, sizeof file_standard ) )
	{
		return false;
	}
	FILE_BASIC_INFO file_basic;
	if( !GetFileInformationByHandleEx( source, FileBasicInfo, &file_basic, sizeof file_basic ) )
	{
		return false;
	}

#ifdef _DEBUG
	ATL::CHandle destination{ CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, 0, source ) };
#else
	ATL::CHandle destination{ CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, source ) };
#endif
	if( destination == INVALID_HANDLE_VALUE )
	{
		destination.Detach();
		return false;
	}
	FILE_DISPOSITION_INFO dispose = { TRUE };
	if( !SetFileInformationByHandle( destination, FileDispositionInfo, &dispose, sizeof dispose ) )
	{
		return false;
	}

	if( file_basic.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE )
	{
		ULONG dummy;
		if( !DeviceIoControl( destination, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &dummy, nullptr ) )
		{
			return false;
		}
	}
	FILE_END_OF_FILE_INFO end_of_file = { file_standard.EndOfFile };
	if( !SetFileInformationByHandle( destination, FileEndOfFileInfo, &end_of_file, sizeof end_of_file ) )
	{
		return false;
	}

	const unsigned split_threshold = 2U * 1024 * 1024 * 1024;
	auto mount_point = std::make_unique<WCHAR[]>( PATHCCH_MAX_CCH );
	if( !GetVolumePathNameW( oldpath, mount_point.get(), PATHCCH_MAX_CCH ) )
	{
		return false;
	}
	ULONG sectors_per_cluster, sector_size, junk;
	if( !GetDiskFreeSpaceW( mount_point.get(), &sectors_per_cluster, &sector_size, &junk, &junk ) )
	{
		return false;
	}
	ULONG cluster_size = sectors_per_cluster * sector_size;
	if( split_threshold % cluster_size != 0 )
	{
		SetLastError( ERROR_NOT_SUPPORTED );
		return false;
	}

	DUPLICATE_EXTENTS_DATA dup_extent = { source };
	for( LONG64 offset = 0, remain = file_standard.AllocationSize.QuadPart; remain > 0; offset += split_threshold, remain -= split_threshold )
	{
		dup_extent.SourceFileOffset.QuadPart = dup_extent.TargetFileOffset.QuadPart = offset;
		dup_extent.ByteCount.QuadPart = std::min<LONG64>( split_threshold, remain );
		_ASSERTE( dup_extent.ByteCount.HighPart == 0 );
		_RPT3( _CRT_WARN, "r=%llx\no=%llx\nb=%llx\n\n", remain, dup_extent.SourceFileOffset.QuadPart, dup_extent.ByteCount.QuadPart );
		ULONG dummy;
		if( !DeviceIoControl( destination, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &dup_extent, sizeof dup_extent, nullptr, 0, &dummy, nullptr ) )
		{
			_CrtDbgBreak();
			return false;
		}
	}

	FILETIME atime = { file_basic.LastAccessTime.LowPart, ULONG( file_basic.LastAccessTime.HighPart ) };
	FILETIME mtime = { file_basic.LastWriteTime.LowPart, ULONG( file_basic.LastWriteTime.HighPart ) };
	SetFileTime( destination, nullptr, &atime, &mtime );
	dispose.DeleteFile = FALSE;
	return SetFileInformationByHandle( destination, FileDispositionInfo, &dispose, sizeof dispose ) != 0;
}
int __cdecl wmain( int argc, PWSTR argv[] )
{
	_CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF );
	_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
	_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE );
	setlocale( LC_ALL, "" );

	if( argc != 3 )
	{
		fprintf(
			stderr,
			"Copy file without actual data write.\n"
			"\n"
			"%ls source destination\n"
			"\n"
			"source       Specifies a file to copy.\n"
			"             source must have placed on the ReFS volume.\n"
			"destination  Specifies new file name.\n"
			"             destination must have placed on the same volume as source.\n",
			PathFindFileNameW( argv[0] )
			);
		return EXIT_FAILURE;
	}
	auto source = std::make_unique<WCHAR[]>( PATHCCH_MAX_CCH );
	auto destination = std::make_unique<WCHAR[]>( PATHCCH_MAX_CCH );
	if( FAILED( PathCchCanonicalizeEx( source.get(), PATHCCH_MAX_CCH, argv[1], PATHCCH_ALLOW_LONG_PATHS ) )
		|| FAILED( PathCchCanonicalizeEx( destination.get(), PATHCCH_MAX_CCH, argv[2], PATHCCH_ALLOW_LONG_PATHS ) ) )
	{
		PrintWindowsError();
		return EXIT_FAILURE;
	}
	if( !reflink( source.get(), destination.get() ) )
	{
		PrintWindowsError();
		return EXIT_FAILURE;
	}
}<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/example/example.pb.h"
#include "tensorflow/core/example/feature.pb.h"
#include "tensorflow/core/framework/partial_tensor_shape.h"
#include "tensorflow/core/framework/stats_aggregator.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/kernels/data/dataset.h"
#include "tensorflow/core/lib/random/random.h"

namespace tensorflow {
namespace {

// This op defines a `Dataset` that passes through its input elements and
// records the latency of producing each element in the context's
// `StatsAggregator`.
//
// TODO(mrry): It is likely that many *StatsDatasetOp kernels will have the
// same or similar structure. We should abstract the common boilerplate into
// a base case and/or investigate how to make general-purpose *StatsDatasetOp
// kernels that use TensorFlow functions to represent their logic. For example,
// if the performance were adequate, we might replace this kernel with an
// implementation that executes functions before and after the `GetNext()` call
// on the input, each executing an op that gets the current time and performing
// the subtraction.
class LatencyStatsDatasetOp : public UnaryDatasetOpKernel {
 public:
  explicit LatencyStatsDatasetOp(OpKernelConstruction* ctx)
      : UnaryDatasetOpKernel(ctx) {}

  void MakeDataset(OpKernelContext* ctx, DatasetBase* input,
                   DatasetBase** output) override {
    string tag;
    OP_REQUIRES_OK(ctx, ParseScalarArgument(ctx, "tag", &tag));
    *output = new Dataset(ctx, input, std::move(tag));
  }

 private:
  class Dataset : public GraphDatasetBase {
   public:
    explicit Dataset(OpKernelContext* ctx, const DatasetBase* input, string tag)
        : GraphDatasetBase(ctx), input_(input), tag_(std::move(tag)) {
      input_->Ref();
    }

    ~Dataset() override { input_->Unref(); }

    std::unique_ptr<IteratorBase> MakeIteratorInternal(
        const string& prefix) const override {
      return std::unique_ptr<IteratorBase>(
          new Iterator({this, strings::StrCat(prefix, "::LatencyStats")}));
    }

    const DataTypeVector& output_dtypes() const override {
      return input_->output_dtypes();
    }
    const std::vector<PartialTensorShape>& output_shapes() const override {
      return input_->output_shapes();
    }

    string DebugString() const override {
      return "LatencyStatsDatasetOp::Dataset";
    }

   protected:
    Status AsGraphDefInternal(OpKernelContext* ctx, DatasetGraphDefBuilder* b,
                              Node** output) const override {
      Node* input_node;
      TF_RETURN_IF_ERROR(b->AddParentDataset(ctx, input_, &input_node));
      Node* tag_node;
      TF_RETURN_IF_ERROR(b->AddScalar(tag_, &tag_node));
      TF_RETURN_IF_ERROR(b->AddDataset(this, {input_node, tag_node}, output));
      return Status::OK();
    }

   private:
    class Iterator : public DatasetIterator<Dataset> {
     public:
      explicit Iterator(const Params& params)
          : DatasetIterator<Dataset>(params) {}

      Status Initialize(IteratorContext* ctx) override {
        return dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_);
      }

      Status GetNextInternal(IteratorContext* ctx,
                             std::vector<Tensor>* out_tensors,
                             bool* end_of_sequence) override {
        tf_shared_lock l(mu_);
        uint64 start = ctx->env()->NowMicros();
        Status s = input_impl_->GetNext(ctx, out_tensors, end_of_sequence);
        uint64 end = ctx->env()->NowMicros();
        auto stats_aggregator = ctx->stats_aggregator();
        if (stats_aggregator && !*end_of_sequence) {
          ctx->stats_aggregator()->AddToHistogram(
              dataset()->tag_, {static_cast<double>(end - start)});
        }
        return s;
      }

     protected:
      Status SaveInternal(IteratorStateWriter* writer) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(SaveParent(writer, input_impl_));
        return Status::OK();
      }

      Status RestoreInternal(IteratorContext* ctx,
                             IteratorStateReader* reader) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(RestoreParent(ctx, reader, input_impl_));
        return Status::OK();
      }

     private:
      mutex mu_;
      std::unique_ptr<IteratorBase> input_impl_ GUARDED_BY(mu_);
    };

    const DatasetBase* const input_;
    const string tag_;
  };
};

class BytesProducedStatsDatasetOp : public UnaryDatasetOpKernel {
 public:
  explicit BytesProducedStatsDatasetOp(OpKernelConstruction* ctx)
      : UnaryDatasetOpKernel(ctx) {}

  void MakeDataset(OpKernelContext* ctx, DatasetBase* input,
                   DatasetBase** output) override {
    string tag;
    OP_REQUIRES_OK(ctx, ParseScalarArgument(ctx, "tag", &tag));
    *output = new Dataset(ctx, input, std::move(tag));
  }

 private:
  class Dataset : public GraphDatasetBase {
   public:
    explicit Dataset(OpKernelContext* ctx, const DatasetBase* input, string tag)
        : GraphDatasetBase(ctx), input_(input), tag_(std::move(tag)) {
      input_->Ref();
    }

    ~Dataset() override { input_->Unref(); }

    std::unique_ptr<IteratorBase> MakeIteratorInternal(
        const string& prefix) const override {
      return std::unique_ptr<IteratorBase>(new Iterator(
          {this, strings::StrCat(prefix, "::BytesProducedStats")}));
    }

    const DataTypeVector& output_dtypes() const override {
      return input_->output_dtypes();
    }
    const std::vector<PartialTensorShape>& output_shapes() const override {
      return input_->output_shapes();
    }

    string DebugString() const override {
      return "BytesProducedStatsDatasetOp::Dataset";
    }

   protected:
    Status AsGraphDefInternal(OpKernelContext* ctx, DatasetGraphDefBuilder* b,
                              Node** output) const override {
      Node* input_node;
      TF_RETURN_IF_ERROR(b->AddParentDataset(ctx, input_, &input_node));
      Node* tag_node;
      TF_RETURN_IF_ERROR(b->AddScalar(tag_, &tag_node));
      TF_RETURN_IF_ERROR(b->AddDataset(this, {input_node, tag_node}, output));
      return Status::OK();
    }

   private:
    class Iterator : public DatasetIterator<Dataset> {
     public:
      explicit Iterator(const Params& params)
          : DatasetIterator<Dataset>(params) {}

      Status Initialize(IteratorContext* ctx) override {
        return dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_);
      }

      Status GetNextInternal(IteratorContext* ctx,
                             std::vector<Tensor>* out_tensors,
                             bool* end_of_sequence) override {
        tf_shared_lock l(mu_);
        Status s = input_impl_->GetNext(ctx, out_tensors, end_of_sequence);
        auto stats_aggregator = ctx->stats_aggregator();
        if (stats_aggregator && s.ok() && !*end_of_sequence) {
          size_t total_bytes = 0;
          for (const Tensor& t : *out_tensors) {
            total_bytes += t.TotalBytes();
          }
          ctx->stats_aggregator()->AddToHistogram(
              dataset()->tag_, {static_cast<double>(total_bytes)});
        }
        return s;
      }

     protected:
      Status SaveInternal(IteratorStateWriter* writer) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(SaveParent(writer, input_impl_));
        return Status::OK();
      }

      Status RestoreInternal(IteratorContext* ctx,
                             IteratorStateReader* reader) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(RestoreParent(ctx, reader, input_impl_));
        return Status::OK();
      }

     private:
      mutex mu_;
      std::unique_ptr<IteratorBase> input_impl_ GUARDED_BY(mu_);
    };

    const DatasetBase* const input_;
    const string tag_;
  };
};

class FeatureStatsDatasetOp : public UnaryDatasetOpKernel {
 public:
  explicit FeatureStatsDatasetOp(OpKernelConstruction* ctx)
      : UnaryDatasetOpKernel(ctx) {}

  void MakeDataset(OpKernelContext* ctx, DatasetBase* input,
                   DatasetBase** output) override {
    string tag;
    OP_REQUIRES_OK(ctx, ParseScalarArgument(ctx, "tag", &tag));
    OP_REQUIRES(ctx, input->output_dtypes()[0] == DT_STRING,
                errors::InvalidArgument("FeatureStatsDataset only supports "
                                        "input with a single `tf.string` "
                                        "component."));
    *output = new Dataset(ctx, input, std::move(tag));
  }

 private:
  class Dataset : public GraphDatasetBase {
   public:
    explicit Dataset(OpKernelContext* ctx, const DatasetBase* input, string tag)
        : GraphDatasetBase(ctx), input_(input), tag_(std::move(tag)) {
      input_->Ref();
    }

    ~Dataset() override { input_->Unref(); }

    std::unique_ptr<IteratorBase> MakeIteratorInternal(
        const string& prefix) const override {
      return std::unique_ptr<IteratorBase>(new Iterator(
          {this, strings::StrCat(prefix, "::FeatureStatsDataset")}));
    }

    const DataTypeVector& output_dtypes() const override {
      return input_->output_dtypes();
    }
    const std::vector<PartialTensorShape>& output_shapes() const override {
      return input_->output_shapes();
    }

    string DebugString() const override {
      return "FeatureStatsDatasetOp::Dataset";
    }

   protected:
    Status AsGraphDefInternal(OpKernelContext* ctx, DatasetGraphDefBuilder* b,
                              Node** output) const override {
      Node* input_node;
      TF_RETURN_IF_ERROR(b->AddParentDataset(ctx, input_, &input_node));
      Node* tag_node;
      TF_RETURN_IF_ERROR(b->AddScalar(tag_, &tag_node));
      TF_RETURN_IF_ERROR(b->AddDataset(this, {input_node, tag_node}, output));
      return Status::OK();
    }

   private:
    class Iterator : public DatasetIterator<Dataset> {
     public:
      explicit Iterator(const Params& params)
          : DatasetIterator<Dataset>(params) {}

      Status Initialize(IteratorContext* ctx) override {
        return dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_);
      }

      Status GetNextInternal(IteratorContext* ctx,
                             std::vector<Tensor>* out_tensors,
                             bool* end_of_sequence) override {
        tf_shared_lock l(mu_);
        Status s = input_impl_->GetNext(ctx, out_tensors, end_of_sequence);
        auto stats_aggregator = ctx->stats_aggregator();
        if (stats_aggregator && s.ok() && !*end_of_sequence) {
          for (const Tensor& t : *out_tensors) {
            auto record_t = t.flat<string>();
            Example example;
            // TODO(shivaniagrawal): redundant parsing here, potential solutions
            // to improve performance is to a) have a potential
            // ParseExampleDataset and collect stats from there and b) make
            // changes to parse_example() where it returns stats as well.
            for (int i = 0; i < record_t.size(); ++i) {
              if (example.ParseFromString(record_t(i))) {
                stats_aggregator->IncrementCounter("examples_count", "trainer",
                                                   1);
                AddStatsFeatures(example, stats_aggregator);
              } else {
                SequenceExample sequence_example;
                if (sequence_example.ParseFromString(record_t(i))) {
                  stats_aggregator->IncrementCounter("sequence_examples_count",
                                                     "trainer", 1);
                  AddStatsFeatures(sequence_example, stats_aggregator);
                }
              }
            }
          }
        }
        return s;
      }

      // TODO(shivaniagrawal): Add features/feature-values to streamz metrics.
      int AddStatsFeatureValues(const Feature& feature) {
        int feature_values_list_size = 0;
        switch (feature.kind_case()) {
          case Feature::kBytesList: {
            feature_values_list_size = feature.bytes_list().value().size();
            break;
          }
          case Feature::kFloatList: {
            feature_values_list_size = feature.float_list().value().size();
            break;
          }
          case Feature::kInt64List: {
            feature_values_list_size = feature.int64_list().value().size();
            break;
          }
          case Feature::KIND_NOT_SET:
            break;
        }
        return feature_values_list_size;
      }

      void AddStatsFeatures(
          const Example& example,
          const std::shared_ptr<StatsAggregator>& stats_aggregator) {
        stats_aggregator->AddToHistogram(
            strings::StrCat(dataset()->tag_, ":features"),
            {static_cast<double>(example.features().feature().size())});

        int feature_values_list_size_sum = 0;
        for (const auto& feature : example.features().feature()) {
          stats_aggregator->IncrementCounter("features_count", "trainer", 1);
          feature_values_list_size_sum += AddStatsFeatureValues(feature.second);
        }
        stats_aggregator->IncrementCounter("feature_values_count", "trainer",
                                           feature_values_list_size_sum);
        stats_aggregator->AddToHistogram(
            strings::StrCat(dataset()->tag_, ":feature-values"),
            {static_cast<double>(feature_values_list_size_sum)});
      }

      void AddStatsFeatures(
          const SequenceExample& example,
          const std::shared_ptr<StatsAggregator>& stats_aggregator) {
        stats_aggregator->AddToHistogram(
            strings::StrCat(dataset()->tag_, ":features"),
            {static_cast<double>(
                example.context().feature().size() +
                example.feature_lists().feature_list().size())});

        int feature_values_list_size_sum = 0;
        for (const auto& feature : example.context().feature()) {
          stats_aggregator->IncrementCounter("features_count", "trainer", 1);
          feature_values_list_size_sum += AddStatsFeatureValues(feature.second);
        }

        for (const auto& feature_list :
             example.feature_lists().feature_list()) {
          stats_aggregator->IncrementCounter("feature_lists_count", "reainer",
                                             1);
          for (const auto& feature : feature_list.second.feature()) {
            feature_values_list_size_sum += AddStatsFeatureValues(feature);
          }
        }
        stats_aggregator->IncrementCounter("feature_values_count", "trainer",
                                           feature_values_list_size_sum);
        stats_aggregator->AddToHistogram(
            strings::StrCat(dataset()->tag_, ":feature-values"),
            {static_cast<double>(feature_values_list_size_sum)});
      }

     protected:
      Status SaveInternal(IteratorStateWriter* writer) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(SaveParent(writer, input_impl_));
        return Status::OK();
      }

      Status RestoreInternal(IteratorContext* ctx,
                             IteratorStateReader* reader) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(RestoreParent(ctx, reader, input_impl_));
        return Status::OK();
      }

     private:
      mutex mu_;
      std::unique_ptr<IteratorBase> input_impl_ GUARDED_BY(mu_);
    };

    const DatasetBase* const input_;
    const string tag_;
  };
};

REGISTER_KERNEL_BUILDER(Name("FeatureStatsDataset").Device(DEVICE_CPU),
                        FeatureStatsDatasetOp);
REGISTER_KERNEL_BUILDER(Name("LatencyStatsDataset").Device(DEVICE_CPU),
                        LatencyStatsDatasetOp);
REGISTER_KERNEL_BUILDER(Name("BytesProducedStatsDataset").Device(DEVICE_CPU),
                        BytesProducedStatsDatasetOp);

}  // namespace
}  // namespace tensorflow
<commit_msg>Removes comment for implemented feature.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/example/example.pb.h"
#include "tensorflow/core/example/feature.pb.h"
#include "tensorflow/core/framework/partial_tensor_shape.h"
#include "tensorflow/core/framework/stats_aggregator.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/kernels/data/dataset.h"
#include "tensorflow/core/lib/random/random.h"

namespace tensorflow {
namespace {

// This op defines a `Dataset` that passes through its input elements and
// records the latency of producing each element in the context's
// `StatsAggregator`.
//
// TODO(mrry): It is likely that many *StatsDatasetOp kernels will have the
// same or similar structure. We should abstract the common boilerplate into
// a base case and/or investigate how to make general-purpose *StatsDatasetOp
// kernels that use TensorFlow functions to represent their logic. For example,
// if the performance were adequate, we might replace this kernel with an
// implementation that executes functions before and after the `GetNext()` call
// on the input, each executing an op that gets the current time and performing
// the subtraction.
class LatencyStatsDatasetOp : public UnaryDatasetOpKernel {
 public:
  explicit LatencyStatsDatasetOp(OpKernelConstruction* ctx)
      : UnaryDatasetOpKernel(ctx) {}

  void MakeDataset(OpKernelContext* ctx, DatasetBase* input,
                   DatasetBase** output) override {
    string tag;
    OP_REQUIRES_OK(ctx, ParseScalarArgument(ctx, "tag", &tag));
    *output = new Dataset(ctx, input, std::move(tag));
  }

 private:
  class Dataset : public GraphDatasetBase {
   public:
    explicit Dataset(OpKernelContext* ctx, const DatasetBase* input, string tag)
        : GraphDatasetBase(ctx), input_(input), tag_(std::move(tag)) {
      input_->Ref();
    }

    ~Dataset() override { input_->Unref(); }

    std::unique_ptr<IteratorBase> MakeIteratorInternal(
        const string& prefix) const override {
      return std::unique_ptr<IteratorBase>(
          new Iterator({this, strings::StrCat(prefix, "::LatencyStats")}));
    }

    const DataTypeVector& output_dtypes() const override {
      return input_->output_dtypes();
    }
    const std::vector<PartialTensorShape>& output_shapes() const override {
      return input_->output_shapes();
    }

    string DebugString() const override {
      return "LatencyStatsDatasetOp::Dataset";
    }

   protected:
    Status AsGraphDefInternal(OpKernelContext* ctx, DatasetGraphDefBuilder* b,
                              Node** output) const override {
      Node* input_node;
      TF_RETURN_IF_ERROR(b->AddParentDataset(ctx, input_, &input_node));
      Node* tag_node;
      TF_RETURN_IF_ERROR(b->AddScalar(tag_, &tag_node));
      TF_RETURN_IF_ERROR(b->AddDataset(this, {input_node, tag_node}, output));
      return Status::OK();
    }

   private:
    class Iterator : public DatasetIterator<Dataset> {
     public:
      explicit Iterator(const Params& params)
          : DatasetIterator<Dataset>(params) {}

      Status Initialize(IteratorContext* ctx) override {
        return dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_);
      }

      Status GetNextInternal(IteratorContext* ctx,
                             std::vector<Tensor>* out_tensors,
                             bool* end_of_sequence) override {
        tf_shared_lock l(mu_);
        uint64 start = ctx->env()->NowMicros();
        Status s = input_impl_->GetNext(ctx, out_tensors, end_of_sequence);
        uint64 end = ctx->env()->NowMicros();
        auto stats_aggregator = ctx->stats_aggregator();
        if (stats_aggregator && !*end_of_sequence) {
          ctx->stats_aggregator()->AddToHistogram(
              dataset()->tag_, {static_cast<double>(end - start)});
        }
        return s;
      }

     protected:
      Status SaveInternal(IteratorStateWriter* writer) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(SaveParent(writer, input_impl_));
        return Status::OK();
      }

      Status RestoreInternal(IteratorContext* ctx,
                             IteratorStateReader* reader) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(RestoreParent(ctx, reader, input_impl_));
        return Status::OK();
      }

     private:
      mutex mu_;
      std::unique_ptr<IteratorBase> input_impl_ GUARDED_BY(mu_);
    };

    const DatasetBase* const input_;
    const string tag_;
  };
};

class BytesProducedStatsDatasetOp : public UnaryDatasetOpKernel {
 public:
  explicit BytesProducedStatsDatasetOp(OpKernelConstruction* ctx)
      : UnaryDatasetOpKernel(ctx) {}

  void MakeDataset(OpKernelContext* ctx, DatasetBase* input,
                   DatasetBase** output) override {
    string tag;
    OP_REQUIRES_OK(ctx, ParseScalarArgument(ctx, "tag", &tag));
    *output = new Dataset(ctx, input, std::move(tag));
  }

 private:
  class Dataset : public GraphDatasetBase {
   public:
    explicit Dataset(OpKernelContext* ctx, const DatasetBase* input, string tag)
        : GraphDatasetBase(ctx), input_(input), tag_(std::move(tag)) {
      input_->Ref();
    }

    ~Dataset() override { input_->Unref(); }

    std::unique_ptr<IteratorBase> MakeIteratorInternal(
        const string& prefix) const override {
      return std::unique_ptr<IteratorBase>(new Iterator(
          {this, strings::StrCat(prefix, "::BytesProducedStats")}));
    }

    const DataTypeVector& output_dtypes() const override {
      return input_->output_dtypes();
    }
    const std::vector<PartialTensorShape>& output_shapes() const override {
      return input_->output_shapes();
    }

    string DebugString() const override {
      return "BytesProducedStatsDatasetOp::Dataset";
    }

   protected:
    Status AsGraphDefInternal(OpKernelContext* ctx, DatasetGraphDefBuilder* b,
                              Node** output) const override {
      Node* input_node;
      TF_RETURN_IF_ERROR(b->AddParentDataset(ctx, input_, &input_node));
      Node* tag_node;
      TF_RETURN_IF_ERROR(b->AddScalar(tag_, &tag_node));
      TF_RETURN_IF_ERROR(b->AddDataset(this, {input_node, tag_node}, output));
      return Status::OK();
    }

   private:
    class Iterator : public DatasetIterator<Dataset> {
     public:
      explicit Iterator(const Params& params)
          : DatasetIterator<Dataset>(params) {}

      Status Initialize(IteratorContext* ctx) override {
        return dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_);
      }

      Status GetNextInternal(IteratorContext* ctx,
                             std::vector<Tensor>* out_tensors,
                             bool* end_of_sequence) override {
        tf_shared_lock l(mu_);
        Status s = input_impl_->GetNext(ctx, out_tensors, end_of_sequence);
        auto stats_aggregator = ctx->stats_aggregator();
        if (stats_aggregator && s.ok() && !*end_of_sequence) {
          size_t total_bytes = 0;
          for (const Tensor& t : *out_tensors) {
            total_bytes += t.TotalBytes();
          }
          ctx->stats_aggregator()->AddToHistogram(
              dataset()->tag_, {static_cast<double>(total_bytes)});
        }
        return s;
      }

     protected:
      Status SaveInternal(IteratorStateWriter* writer) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(SaveParent(writer, input_impl_));
        return Status::OK();
      }

      Status RestoreInternal(IteratorContext* ctx,
                             IteratorStateReader* reader) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(RestoreParent(ctx, reader, input_impl_));
        return Status::OK();
      }

     private:
      mutex mu_;
      std::unique_ptr<IteratorBase> input_impl_ GUARDED_BY(mu_);
    };

    const DatasetBase* const input_;
    const string tag_;
  };
};

class FeatureStatsDatasetOp : public UnaryDatasetOpKernel {
 public:
  explicit FeatureStatsDatasetOp(OpKernelConstruction* ctx)
      : UnaryDatasetOpKernel(ctx) {}

  void MakeDataset(OpKernelContext* ctx, DatasetBase* input,
                   DatasetBase** output) override {
    string tag;
    OP_REQUIRES_OK(ctx, ParseScalarArgument(ctx, "tag", &tag));
    OP_REQUIRES(ctx, input->output_dtypes()[0] == DT_STRING,
                errors::InvalidArgument("FeatureStatsDataset only supports "
                                        "input with a single `tf.string` "
                                        "component."));
    *output = new Dataset(ctx, input, std::move(tag));
  }

 private:
  class Dataset : public GraphDatasetBase {
   public:
    explicit Dataset(OpKernelContext* ctx, const DatasetBase* input, string tag)
        : GraphDatasetBase(ctx), input_(input), tag_(std::move(tag)) {
      input_->Ref();
    }

    ~Dataset() override { input_->Unref(); }

    std::unique_ptr<IteratorBase> MakeIteratorInternal(
        const string& prefix) const override {
      return std::unique_ptr<IteratorBase>(new Iterator(
          {this, strings::StrCat(prefix, "::FeatureStatsDataset")}));
    }

    const DataTypeVector& output_dtypes() const override {
      return input_->output_dtypes();
    }
    const std::vector<PartialTensorShape>& output_shapes() const override {
      return input_->output_shapes();
    }

    string DebugString() const override {
      return "FeatureStatsDatasetOp::Dataset";
    }

   protected:
    Status AsGraphDefInternal(OpKernelContext* ctx, DatasetGraphDefBuilder* b,
                              Node** output) const override {
      Node* input_node;
      TF_RETURN_IF_ERROR(b->AddParentDataset(ctx, input_, &input_node));
      Node* tag_node;
      TF_RETURN_IF_ERROR(b->AddScalar(tag_, &tag_node));
      TF_RETURN_IF_ERROR(b->AddDataset(this, {input_node, tag_node}, output));
      return Status::OK();
    }

   private:
    class Iterator : public DatasetIterator<Dataset> {
     public:
      explicit Iterator(const Params& params)
          : DatasetIterator<Dataset>(params) {}

      Status Initialize(IteratorContext* ctx) override {
        return dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_);
      }

      Status GetNextInternal(IteratorContext* ctx,
                             std::vector<Tensor>* out_tensors,
                             bool* end_of_sequence) override {
        tf_shared_lock l(mu_);
        Status s = input_impl_->GetNext(ctx, out_tensors, end_of_sequence);
        auto stats_aggregator = ctx->stats_aggregator();
        if (stats_aggregator && s.ok() && !*end_of_sequence) {
          for (const Tensor& t : *out_tensors) {
            auto record_t = t.flat<string>();
            Example example;
            // TODO(b/111553342): redundant parsing here, potential solutions
            // to improve performance is to a) have a potential
            // ParseExampleDataset and collect stats from there and b) make
            // changes to parse_example() where it returns stats as well.
            for (int i = 0; i < record_t.size(); ++i) {
              if (example.ParseFromString(record_t(i))) {
                stats_aggregator->IncrementCounter("examples_count", "trainer",
                                                   1);
                AddStatsFeatures(example, stats_aggregator);
              } else {
                SequenceExample sequence_example;
                if (sequence_example.ParseFromString(record_t(i))) {
                  stats_aggregator->IncrementCounter("sequence_examples_count",
                                                     "trainer", 1);
                  AddStatsFeatures(sequence_example, stats_aggregator);
                }
              }
            }
          }
        }
        return s;
      }

      int AddStatsFeatureValues(const Feature& feature) {
        int feature_values_list_size = 0;
        switch (feature.kind_case()) {
          case Feature::kBytesList: {
            feature_values_list_size = feature.bytes_list().value().size();
            break;
          }
          case Feature::kFloatList: {
            feature_values_list_size = feature.float_list().value().size();
            break;
          }
          case Feature::kInt64List: {
            feature_values_list_size = feature.int64_list().value().size();
            break;
          }
          case Feature::KIND_NOT_SET:
            break;
        }
        return feature_values_list_size;
      }

      void AddStatsFeatures(
          const Example& example,
          const std::shared_ptr<StatsAggregator>& stats_aggregator) {
        stats_aggregator->AddToHistogram(
            strings::StrCat(dataset()->tag_, ":features"),
            {static_cast<double>(example.features().feature().size())});

        int feature_values_list_size_sum = 0;
        for (const auto& feature : example.features().feature()) {
          stats_aggregator->IncrementCounter("features_count", "trainer", 1);
          feature_values_list_size_sum += AddStatsFeatureValues(feature.second);
        }
        stats_aggregator->IncrementCounter("feature_values_count", "trainer",
                                           feature_values_list_size_sum);
        stats_aggregator->AddToHistogram(
            strings::StrCat(dataset()->tag_, ":feature-values"),
            {static_cast<double>(feature_values_list_size_sum)});
      }

      void AddStatsFeatures(
          const SequenceExample& example,
          const std::shared_ptr<StatsAggregator>& stats_aggregator) {
        stats_aggregator->AddToHistogram(
            strings::StrCat(dataset()->tag_, ":features"),
            {static_cast<double>(
                example.context().feature().size() +
                example.feature_lists().feature_list().size())});

        int feature_values_list_size_sum = 0;
        for (const auto& feature : example.context().feature()) {
          stats_aggregator->IncrementCounter("features_count", "trainer", 1);
          feature_values_list_size_sum += AddStatsFeatureValues(feature.second);
        }

        for (const auto& feature_list :
             example.feature_lists().feature_list()) {
          stats_aggregator->IncrementCounter("feature_lists_count", "reainer",
                                             1);
          for (const auto& feature : feature_list.second.feature()) {
            feature_values_list_size_sum += AddStatsFeatureValues(feature);
          }
        }
        stats_aggregator->IncrementCounter("feature_values_count", "trainer",
                                           feature_values_list_size_sum);
        stats_aggregator->AddToHistogram(
            strings::StrCat(dataset()->tag_, ":feature-values"),
            {static_cast<double>(feature_values_list_size_sum)});
      }

     protected:
      Status SaveInternal(IteratorStateWriter* writer) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(SaveParent(writer, input_impl_));
        return Status::OK();
      }

      Status RestoreInternal(IteratorContext* ctx,
                             IteratorStateReader* reader) override {
        mutex_lock l(mu_);
        TF_RETURN_IF_ERROR(RestoreParent(ctx, reader, input_impl_));
        return Status::OK();
      }

     private:
      mutex mu_;
      std::unique_ptr<IteratorBase> input_impl_ GUARDED_BY(mu_);
    };

    const DatasetBase* const input_;
    const string tag_;
  };
};

REGISTER_KERNEL_BUILDER(Name("FeatureStatsDataset").Device(DEVICE_CPU),
                        FeatureStatsDatasetOp);
REGISTER_KERNEL_BUILDER(Name("LatencyStatsDataset").Device(DEVICE_CPU),
                        LatencyStatsDatasetOp);
REGISTER_KERNEL_BUILDER(Name("BytesProducedStatsDataset").Device(DEVICE_CPU),
                        BytesProducedStatsDatasetOp);

}  // namespace
}  // namespace tensorflow
<|endoftext|>


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

#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include <vector>
using namespace llvm;

// Check that the ArrayRef-of-pointer converting constructor only allows adding
// cv qualifiers (not removing them, or otherwise changing the type)
static_assert(
    std::is_convertible<ArrayRef<int *>, ArrayRef<const int *>>::value,
    "Adding const");
static_assert(
    std::is_convertible<ArrayRef<int *>, ArrayRef<volatile int *>>::value,
    "Adding volatile");
static_assert(!std::is_convertible<ArrayRef<int *>, ArrayRef<float *>>::value,
              "Changing pointer of one type to a pointer of another");
static_assert(
    !std::is_convertible<ArrayRef<const int *>, ArrayRef<int *>>::value,
    "Removing const");
static_assert(
    !std::is_convertible<ArrayRef<volatile int *>, ArrayRef<int *>>::value,
    "Removing volatile");

// Check that we can't accidentally assign a temporary location to an ArrayRef.
// (Unfortunately we can't make use of the same thing with constructors.)
//
// Disable this check under MSVC; even MSVC 2015 isn't inconsistent between
// std::is_assignable and actually writing such an assignment.
#if !defined(_MSC_VER)
static_assert(
    !std::is_assignable<ArrayRef<int *>, int *>::value,
    "Assigning from single prvalue element");
static_assert(
    !std::is_assignable<ArrayRef<int *>, int * &&>::value,
    "Assigning from single xvalue element");
static_assert(
    std::is_assignable<ArrayRef<int *>, int * &>::value,
    "Assigning from single lvalue element");
static_assert(
    !std::is_assignable<ArrayRef<int *>, std::initializer_list<int *>>::value,
    "Assigning from an initializer list");
#endif

namespace {

TEST(ArrayRefTest, AllocatorCopy) {
  BumpPtrAllocator Alloc;
  static const uint16_t Words1[] = { 1, 4, 200, 37 };
  ArrayRef<uint16_t> Array1 = makeArrayRef(Words1, 4);
  static const uint16_t Words2[] = { 11, 4003, 67, 64000, 13 };
  ArrayRef<uint16_t> Array2 = makeArrayRef(Words2, 5);
  ArrayRef<uint16_t> Array1c = Array1.copy(Alloc);
  ArrayRef<uint16_t> Array2c = Array2.copy(Alloc);
  EXPECT_TRUE(Array1.equals(Array1c));
  EXPECT_NE(Array1.data(), Array1c.data());
  EXPECT_TRUE(Array2.equals(Array2c));
  EXPECT_NE(Array2.data(), Array2c.data());

  // Check that copy can cope with uninitialized memory.
  struct NonAssignable {
    const char *Ptr;

    NonAssignable(const char *Ptr) : Ptr(Ptr) {}
    NonAssignable(const NonAssignable &RHS) = default;
    void operator=(const NonAssignable &RHS) { assert(RHS.Ptr != nullptr); }
    bool operator==(const NonAssignable &RHS) const { return Ptr == RHS.Ptr; }
  } Array3Src[] = {"hello", "world"};
  ArrayRef<NonAssignable> Array3Copy = makeArrayRef(Array3Src).copy(Alloc);
  EXPECT_EQ(makeArrayRef(Array3Src), Array3Copy);
  EXPECT_NE(makeArrayRef(Array3Src).data(), Array3Copy.data());
}

TEST(ArrayRefTest, DropBack) {
  static const int TheNumbers[] = {4, 8, 15, 16, 23, 42};
  ArrayRef<int> AR1(TheNumbers);
  ArrayRef<int> AR2(TheNumbers, AR1.size() - 1);
  EXPECT_TRUE(AR1.drop_back().equals(AR2));

  // Check that drop_back accepts size_t-sized numbers.
  ArrayRef<char> AR3((const char *)0x10000, SIZE_MAX - 0x10000);
  EXPECT_EQ(1U, AR3.drop_back(AR3.size() - 1).size());
}

TEST(ArrayRefTest, DropFront) {
  static const int TheNumbers[] = {4, 8, 15, 16, 23, 42};
  ArrayRef<int> AR1(TheNumbers);
  ArrayRef<int> AR2(&TheNumbers[2], AR1.size() - 2);
  EXPECT_TRUE(AR1.drop_front(2).equals(AR2));

  // Check that drop_front accepts size_t-sized numbers.
  ArrayRef<char> AR3((const char *)0x10000, SIZE_MAX - 0x10000);
  EXPECT_EQ(1U, AR3.drop_front(AR3.size() - 1).size());
}

TEST(ArrayRefTest, KeepBack) {
  static const int TheNumbers[] = {4, 8, 15, 16, 23, 42};
  ArrayRef<int> AR1(TheNumbers);
  ArrayRef<int> AR2(AR1.end() - 1, 1);
  EXPECT_TRUE(AR1.keep_back().equals(AR2));
}

TEST(ArrayRefTest, KeepFront) {
  static const int TheNumbers[] = {4, 8, 15, 16, 23, 42};
  ArrayRef<int> AR1(TheNumbers);
  ArrayRef<int> AR2(AR1.data(), 2);
  EXPECT_TRUE(AR1.keep_front(2).equals(AR2));
}

TEST(ArrayRefTest, Equals) {
  static const int A1[] = {1, 2, 3, 4, 5, 6, 7, 8};
  ArrayRef<int> AR1(A1);
  EXPECT_TRUE(AR1.equals({1, 2, 3, 4, 5, 6, 7, 8}));
  EXPECT_FALSE(AR1.equals({8, 1, 2, 4, 5, 6, 6, 7}));
  EXPECT_FALSE(AR1.equals({2, 4, 5, 6, 6, 7, 8, 1}));
  EXPECT_FALSE(AR1.equals({0, 1, 2, 4, 5, 6, 6, 7}));
  EXPECT_FALSE(AR1.equals({1, 2, 42, 4, 5, 6, 7, 8}));
  EXPECT_FALSE(AR1.equals({42, 2, 3, 4, 5, 6, 7, 8}));
  EXPECT_FALSE(AR1.equals({1, 2, 3, 4, 5, 6, 7, 42}));
  EXPECT_FALSE(AR1.equals({1, 2, 3, 4, 5, 6, 7}));
  EXPECT_FALSE(AR1.equals({1, 2, 3, 4, 5, 6, 7, 8, 9}));

  ArrayRef<int> AR1a = AR1.drop_back();
  EXPECT_TRUE(AR1a.equals({1, 2, 3, 4, 5, 6, 7}));
  EXPECT_FALSE(AR1a.equals({1, 2, 3, 4, 5, 6, 7, 8}));

  ArrayRef<int> AR1b = AR1a.slice(2, 4);
  EXPECT_TRUE(AR1b.equals({3, 4, 5, 6}));
  EXPECT_FALSE(AR1b.equals({2, 3, 4, 5, 6}));
  EXPECT_FALSE(AR1b.equals({3, 4, 5, 6, 7}));
}

TEST(ArrayRefTest, EmptyEquals) {
  EXPECT_TRUE(ArrayRef<unsigned>() == ArrayRef<unsigned>());
}

TEST(ArrayRefTest, Slice) {
  // Check that slice accepts size_t-sized numbers.
  ArrayRef<char> AR((const char *)0x10000, SIZE_MAX - 0x10000);
  EXPECT_EQ(1U, AR.slice(AR.size() - 1).size());
  EXPECT_EQ(AR.size() - 1, AR.slice(1, AR.size() - 1).size());
}

TEST(ArrayRefTest, ConstConvert) {
  int buf[4];
  for (int i = 0; i < 4; ++i)
    buf[i] = i;

  static int *A[] = {&buf[0], &buf[1], &buf[2], &buf[3]};
  ArrayRef<const int *> a((ArrayRef<int *>(A)));
  a = ArrayRef<int *>(A);
}

static std::vector<int> ReturnTest12() { return {1, 2}; }
static void ArgTest12(ArrayRef<int> A) {
  EXPECT_EQ(2U, A.size());
  EXPECT_EQ(1, A[0]);
  EXPECT_EQ(2, A[1]);
}

TEST(ArrayRefTest, InitializerList) {
  ArrayRef<int> A = { 0, 1, 2, 3, 4 };
  for (int i = 0; i < 5; ++i)
    EXPECT_EQ(i, A[i]);

  std::vector<int> B = ReturnTest12();
  A = B;
  EXPECT_EQ(1, A[0]);
  EXPECT_EQ(2, A[1]);

  ArgTest12({1, 2});
}

TEST(ArrayRefTest, EmptyInitializerList) {
  ArrayRef<int> A = {};
  EXPECT_TRUE(A.empty());

  A = {};
  EXPECT_TRUE(A.empty());
}

// Test that makeArrayRef works on ArrayRef (no-op)
TEST(ArrayRefTest, makeArrayRef) {
  static const int A1[] = {1, 2, 3, 4, 5, 6, 7, 8};

  // No copy expected for non-const ArrayRef (true no-op)
  ArrayRef<int> AR1(A1);
  ArrayRef<int> &AR1Ref = makeArrayRef(AR1);
  EXPECT_EQ(&AR1, &AR1Ref);

  // A copy is expected for non-const ArrayRef (thin copy)
  const ArrayRef<int> AR2(A1);
  const ArrayRef<int> &AR2Ref = makeArrayRef(AR2);
  EXPECT_NE(&AR2Ref, &AR2);
  EXPECT_TRUE(AR2.equals(AR2Ref));
}

} // end anonymous namespace
<commit_msg>Fix unit test after function name change.<commit_after>//===- llvm/unittest/ADT/ArrayRefTest.cpp - ArrayRef unit tests -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include <vector>
using namespace llvm;

// Check that the ArrayRef-of-pointer converting constructor only allows adding
// cv qualifiers (not removing them, or otherwise changing the type)
static_assert(
    std::is_convertible<ArrayRef<int *>, ArrayRef<const int *>>::value,
    "Adding const");
static_assert(
    std::is_convertible<ArrayRef<int *>, ArrayRef<volatile int *>>::value,
    "Adding volatile");
static_assert(!std::is_convertible<ArrayRef<int *>, ArrayRef<float *>>::value,
              "Changing pointer of one type to a pointer of another");
static_assert(
    !std::is_convertible<ArrayRef<const int *>, ArrayRef<int *>>::value,
    "Removing const");
static_assert(
    !std::is_convertible<ArrayRef<volatile int *>, ArrayRef<int *>>::value,
    "Removing volatile");

// Check that we can't accidentally assign a temporary location to an ArrayRef.
// (Unfortunately we can't make use of the same thing with constructors.)
//
// Disable this check under MSVC; even MSVC 2015 isn't inconsistent between
// std::is_assignable and actually writing such an assignment.
#if !defined(_MSC_VER)
static_assert(
    !std::is_assignable<ArrayRef<int *>, int *>::value,
    "Assigning from single prvalue element");
static_assert(
    !std::is_assignable<ArrayRef<int *>, int * &&>::value,
    "Assigning from single xvalue element");
static_assert(
    std::is_assignable<ArrayRef<int *>, int * &>::value,
    "Assigning from single lvalue element");
static_assert(
    !std::is_assignable<ArrayRef<int *>, std::initializer_list<int *>>::value,
    "Assigning from an initializer list");
#endif

namespace {

TEST(ArrayRefTest, AllocatorCopy) {
  BumpPtrAllocator Alloc;
  static const uint16_t Words1[] = { 1, 4, 200, 37 };
  ArrayRef<uint16_t> Array1 = makeArrayRef(Words1, 4);
  static const uint16_t Words2[] = { 11, 4003, 67, 64000, 13 };
  ArrayRef<uint16_t> Array2 = makeArrayRef(Words2, 5);
  ArrayRef<uint16_t> Array1c = Array1.copy(Alloc);
  ArrayRef<uint16_t> Array2c = Array2.copy(Alloc);
  EXPECT_TRUE(Array1.equals(Array1c));
  EXPECT_NE(Array1.data(), Array1c.data());
  EXPECT_TRUE(Array2.equals(Array2c));
  EXPECT_NE(Array2.data(), Array2c.data());

  // Check that copy can cope with uninitialized memory.
  struct NonAssignable {
    const char *Ptr;

    NonAssignable(const char *Ptr) : Ptr(Ptr) {}
    NonAssignable(const NonAssignable &RHS) = default;
    void operator=(const NonAssignable &RHS) { assert(RHS.Ptr != nullptr); }
    bool operator==(const NonAssignable &RHS) const { return Ptr == RHS.Ptr; }
  } Array3Src[] = {"hello", "world"};
  ArrayRef<NonAssignable> Array3Copy = makeArrayRef(Array3Src).copy(Alloc);
  EXPECT_EQ(makeArrayRef(Array3Src), Array3Copy);
  EXPECT_NE(makeArrayRef(Array3Src).data(), Array3Copy.data());
}

TEST(ArrayRefTest, DropBack) {
  static const int TheNumbers[] = {4, 8, 15, 16, 23, 42};
  ArrayRef<int> AR1(TheNumbers);
  ArrayRef<int> AR2(TheNumbers, AR1.size() - 1);
  EXPECT_TRUE(AR1.drop_back().equals(AR2));

  // Check that drop_back accepts size_t-sized numbers.
  ArrayRef<char> AR3((const char *)0x10000, SIZE_MAX - 0x10000);
  EXPECT_EQ(1U, AR3.drop_back(AR3.size() - 1).size());
}

TEST(ArrayRefTest, DropFront) {
  static const int TheNumbers[] = {4, 8, 15, 16, 23, 42};
  ArrayRef<int> AR1(TheNumbers);
  ArrayRef<int> AR2(&TheNumbers[2], AR1.size() - 2);
  EXPECT_TRUE(AR1.drop_front(2).equals(AR2));

  // Check that drop_front accepts size_t-sized numbers.
  ArrayRef<char> AR3((const char *)0x10000, SIZE_MAX - 0x10000);
  EXPECT_EQ(1U, AR3.drop_front(AR3.size() - 1).size());
}

TEST(ArrayRefTest, TakeBack) {
  static const int TheNumbers[] = {4, 8, 15, 16, 23, 42};
  ArrayRef<int> AR1(TheNumbers);
  ArrayRef<int> AR2(AR1.end() - 1, 1);
  EXPECT_TRUE(AR1.take_back().equals(AR2));
}

TEST(ArrayRefTest, TakeFront) {
  static const int TheNumbers[] = {4, 8, 15, 16, 23, 42};
  ArrayRef<int> AR1(TheNumbers);
  ArrayRef<int> AR2(AR1.data(), 2);
  EXPECT_TRUE(AR1.take_front(2).equals(AR2));
}

TEST(ArrayRefTest, Equals) {
  static const int A1[] = {1, 2, 3, 4, 5, 6, 7, 8};
  ArrayRef<int> AR1(A1);
  EXPECT_TRUE(AR1.equals({1, 2, 3, 4, 5, 6, 7, 8}));
  EXPECT_FALSE(AR1.equals({8, 1, 2, 4, 5, 6, 6, 7}));
  EXPECT_FALSE(AR1.equals({2, 4, 5, 6, 6, 7, 8, 1}));
  EXPECT_FALSE(AR1.equals({0, 1, 2, 4, 5, 6, 6, 7}));
  EXPECT_FALSE(AR1.equals({1, 2, 42, 4, 5, 6, 7, 8}));
  EXPECT_FALSE(AR1.equals({42, 2, 3, 4, 5, 6, 7, 8}));
  EXPECT_FALSE(AR1.equals({1, 2, 3, 4, 5, 6, 7, 42}));
  EXPECT_FALSE(AR1.equals({1, 2, 3, 4, 5, 6, 7}));
  EXPECT_FALSE(AR1.equals({1, 2, 3, 4, 5, 6, 7, 8, 9}));

  ArrayRef<int> AR1a = AR1.drop_back();
  EXPECT_TRUE(AR1a.equals({1, 2, 3, 4, 5, 6, 7}));
  EXPECT_FALSE(AR1a.equals({1, 2, 3, 4, 5, 6, 7, 8}));

  ArrayRef<int> AR1b = AR1a.slice(2, 4);
  EXPECT_TRUE(AR1b.equals({3, 4, 5, 6}));
  EXPECT_FALSE(AR1b.equals({2, 3, 4, 5, 6}));
  EXPECT_FALSE(AR1b.equals({3, 4, 5, 6, 7}));
}

TEST(ArrayRefTest, EmptyEquals) {
  EXPECT_TRUE(ArrayRef<unsigned>() == ArrayRef<unsigned>());
}

TEST(ArrayRefTest, Slice) {
  // Check that slice accepts size_t-sized numbers.
  ArrayRef<char> AR((const char *)0x10000, SIZE_MAX - 0x10000);
  EXPECT_EQ(1U, AR.slice(AR.size() - 1).size());
  EXPECT_EQ(AR.size() - 1, AR.slice(1, AR.size() - 1).size());
}

TEST(ArrayRefTest, ConstConvert) {
  int buf[4];
  for (int i = 0; i < 4; ++i)
    buf[i] = i;

  static int *A[] = {&buf[0], &buf[1], &buf[2], &buf[3]};
  ArrayRef<const int *> a((ArrayRef<int *>(A)));
  a = ArrayRef<int *>(A);
}

static std::vector<int> ReturnTest12() { return {1, 2}; }
static void ArgTest12(ArrayRef<int> A) {
  EXPECT_EQ(2U, A.size());
  EXPECT_EQ(1, A[0]);
  EXPECT_EQ(2, A[1]);
}

TEST(ArrayRefTest, InitializerList) {
  ArrayRef<int> A = { 0, 1, 2, 3, 4 };
  for (int i = 0; i < 5; ++i)
    EXPECT_EQ(i, A[i]);

  std::vector<int> B = ReturnTest12();
  A = B;
  EXPECT_EQ(1, A[0]);
  EXPECT_EQ(2, A[1]);

  ArgTest12({1, 2});
}

TEST(ArrayRefTest, EmptyInitializerList) {
  ArrayRef<int> A = {};
  EXPECT_TRUE(A.empty());

  A = {};
  EXPECT_TRUE(A.empty());
}

// Test that makeArrayRef works on ArrayRef (no-op)
TEST(ArrayRefTest, makeArrayRef) {
  static const int A1[] = {1, 2, 3, 4, 5, 6, 7, 8};

  // No copy expected for non-const ArrayRef (true no-op)
  ArrayRef<int> AR1(A1);
  ArrayRef<int> &AR1Ref = makeArrayRef(AR1);
  EXPECT_EQ(&AR1, &AR1Ref);

  // A copy is expected for non-const ArrayRef (thin copy)
  const ArrayRef<int> AR2(A1);
  const ArrayRef<int> &AR2Ref = makeArrayRef(AR2);
  EXPECT_NE(&AR2Ref, &AR2);
  EXPECT_TRUE(AR2.equals(AR2Ref));
}

} // end anonymous namespace
<|endoftext|>