青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天行健 君子當(dāng)自強(qiáng)而不息

DXUT源碼分析 ---- 類CGrowableArray

CGrowableArray是DXUT實(shí)現(xiàn)的一個可自動增長的模板類數(shù)組,類似于STL里的vector,該類的實(shí)現(xiàn)在DXUTmisc.h里。


首先來看看它的定義部分:

//--------------------------------------------------------------------------------------
// A growable array
//--------------------------------------------------------------------------------------
template< typename TYPE >
class CGrowableArray
{
public:
    CGrowableArray()  
    { 
        m_pData        
= NULL; 
        m_nSize        
= 0
        m_nMaxSize    
= 0
    }

    CGrowableArray( 
const CGrowableArray<TYPE>& a ) 
    { 
        
forint i=0; i < a.m_nSize; i++ ) 
            Add( a.m_pData[i] ); 
    }

    
~CGrowableArray() 
    { 
        RemoveAll(); 
    }

    
const TYPE& operator[]( int nIndex ) const  { return GetAt( nIndex ); }
    TYPE
& operator[]( int nIndex )                { return GetAt( nIndex ); }
   
    CGrowableArray
& operator=const CGrowableArray<TYPE>& a ) 
    { 
        
ifthis == &a ) 
            
return *this
        
        RemoveAll(); 
        
        
forint i=0; i < a.m_nSize; i++ ) 
            Add( a.m_pData[i] ); 
        
        
return *this
    }

    HRESULT SetSize( 
int nNewMaxSize );
    HRESULT Add( 
const TYPE& value );
    HRESULT Insert( 
int nIndex, const TYPE& value );
    HRESULT SetAt( 
int nIndex, const TYPE& value );

    TYPE
&   GetAt( int nIndex ) 
    { 
        assert( nIndex 
>= 0 && nIndex < m_nSize ); 
        
return m_pData[nIndex]; 
    }

    
int     GetSize() const                    { return m_nSize; }
    TYPE
*   GetData()                        { return m_pData; }
    
bool    Contains( const TYPE& value )    { return ( -1 != IndexOf( value ) ); }

    
int IndexOf( const TYPE& value ) 
    { 
        
return ( m_nSize > 0 ) ? IndexOf( value, 0, m_nSize ) : -1
    }

    
int IndexOf( const TYPE& value, int iStart ) 
    { 
        
return IndexOf( value, iStart, m_nSize - iStart ); 
    }

    
int IndexOf( const TYPE& value, int nIndex, int nNumElements );

    
int LastIndexOf( const TYPE& value ) 
    { 
        
return ( m_nSize > 0 ) ? LastIndexOf( value, m_nSize-1, m_nSize ) : -1
    }

    
int LastIndexOf( const TYPE& value, int nIndex ) 
    { 
        
return LastIndexOf( value, nIndex, nIndex+1 ); 
    }

    
int LastIndexOf( const TYPE& value, int nIndex, int nNumElements );

    HRESULT Remove( 
int nIndex );
    
void    RemoveAll() { SetSize(0); }

protected:
    TYPE
* m_pData;      // the actual array of data
    int m_nSize;        // # of elements (upperBound - 1)
    int m_nMaxSize;     // max allocated

    HRESULT SetSizeInternal( 
int nNewMaxSize );  // This version doesn't call constructor or destructor.
};

 

 

SetSizeInternal() 分析

template< typename TYPE >
HRESULT CGrowableArray
<TYPE>::SetSizeInternal( int nNewMaxSize )
{
    
if( nNewMaxSize < 0 )
    {
        assert( 
false );
        
return E_INVALIDARG;
    }

    
if( nNewMaxSize == 0 )
    {
        
// Shrink to 0 size & cleanup
        if( m_pData )
        {
            free( m_pData );
            m_pData 
= NULL;
        }

        m_nMaxSize 
= 0;
        m_nSize       
= 0;
    }
    
else if( m_pData == NULL || nNewMaxSize > m_nMaxSize )
    {
        
// Grow array
        int nGrowBy = ( m_nMaxSize == 0 ) ? 16 : m_nMaxSize;
        nNewMaxSize 
= __max( nNewMaxSize, m_nMaxSize + nGrowBy );

        TYPE
* pDataNew = (TYPE*) realloc( m_pData, nNewMaxSize * sizeof(TYPE) );
        
if( pDataNew == NULL )
            
return E_OUTOFMEMORY;

        m_pData       
= pDataNew;
        m_nMaxSize 
= nNewMaxSize;
    }

    
return S_OK;
}

SetSizeInternal()是protected類型的方法,主要供其他方法內(nèi)部調(diào)用,函數(shù)首先檢查nNewMaxSize是否合法,如果nNewMaxSize為0則釋放分配的內(nèi)存,如果m_pData為NULL或者指定的nNewMaxSize大于原先分配的內(nèi)存大小m_nMaxSize,則重新分配內(nèi)存。

// Grow array
int nGrowBy = ( m_nMaxSize == 0 ) ? 16 : m_nMaxSize;  

如果m_nMaxSize為0,意味著沒有為m_nMaxSize指定大小,則將nGrowBy賦值為16,即增加的內(nèi)存大小為16 * sizeof(TYPE);若指定了m_nMaxSize,則增加的大小為m_nMaxSize * sizeof(TYPE),即將分配內(nèi)存調(diào)整為原來的兩倍。

nNewMaxSize = __max( nNewMaxSize, m_nMaxSize + nGrowBy );

#define __max(a,b) (((a) > (b)) ? (a) : (b))

nNewMaxSize在新指定分配內(nèi)存大小與自動增長的內(nèi)存m_nMaxSize + nGrowBy 中取一個較大的值。

TYPE* pDataNew = (TYPE*) realloc( m_pData, nNewMaxSize * sizeof(TYPE) );
if( pDataNew == NULL )
        return E_OUTOFMEMORY;

m_pData       = pDataNew;
m_nMaxSize = nNewMaxSize;

pDataNew為指向重新分配內(nèi)存的指針,m_pData = pDataNew將m_pData指向新分配的內(nèi)存,m_nMaxSize = nNewMaxSize更新分配后內(nèi)存的最大尺寸。

函數(shù)realloc()的聲明如下:

Reallocate memory blocks.

 
void *realloc(
void *memblock,
size_t size
);

Parameters

memblock
Pointer to previously allocated memory block.
size
New size in bytes.

Return Value

realloc returns a void pointer to the reallocated (and possibly moved) memory block.

If there is not enough available memory to expand the block to the given size, the original block is left unchanged, and NULL is returned.

If size is zero, then the block pointed to by memblock is freed; the return value is NULL, and memblock is left pointing at a freed block.

The return value points to a storage space that is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.

Remarks

The realloc function changes the size of an allocated memory block. The memblock argument points to the beginning of the memory block. If memblock is NULL, realloc behaves the same way as malloc and allocates a new block of size bytes. If memblock is not NULL, it should be a pointer returned by a previous call to calloc, malloc, or realloc.

The size argument gives the new size of the block, in bytes. The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block can be in a different location. Because the new block can be in a new memory location, the pointer returned by realloc is not guaranteed to be the pointer passed through the memblock argument.

In Visual C++ 2005, realloc sets errno to ENOMEM if the memory allocation fails or if the amount of memory requested exceeds _HEAP_MAXREQ. For information on this and other error codes, see errno, _doserrno, _sys_errlist, and _sys_nerr.

realloc calls malloc in order to use the C++ _set_new_mode function to set the new handler mode. The new handler mode indicates whether, on failure, malloc is to call the new handler routine as set by _set_new_handler. By default, malloc does not call the new handler routine on failure to allocate memory. You can override this default behavior so that, when realloc fails to allocate memory, malloc calls the new handler routine in the same way that the new operator does when it fails for the same reason. To override the default, call

_set_new_mode(1)

early in ones program, or link with NEWMODE.OBJ (see Link Options).

When the application is linked with a debug version of the C run-time libraries, realloc resolves to _realloc_dbg. For more information about how the heap is managed during the debugging process, see The CRT Debug Heap.

realloc is marked __declspec(noalias) and __declspec(restrict), meaning that the function is guaranteed not to modify global variables, and that the pointer returned is not aliased. For more information, see noalias and restrict.

Requirements

Routine Required header Compatibility
realloc <stdlib.h> and <malloc.h> ANSI, Windows 95, Windows 98, Windows 98 Second Edition, Windows Millennium Edition, Windows NT 4.0, Windows 2000, Windows XP Home Edition, Windows XP Professional, Windows Server 2003

For additional compatibility information, see Compatibility in the Introduction.

Example

// crt_realloc.c
// This program allocates a block of memory for buffer and then uses _msize to display the size of that
// block. Next, it uses realloc to expand the amount of memory used by buffer and then calls _msize again to
// display the new amount of memory allocated to buffer.

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

int main( void )
{
long *buffer, *oldbuffer;
size_t size;

if( (buffer = (long *)malloc( 1000 * sizeof( long ) )) == NULL )
exit( 1 );

size = _msize( buffer );
printf( "Size of block after malloc of 1000 longs: %u\n", size );

// Reallocate and show new size:
oldbuffer = buffer; // save pointer in case realloc fails
if( (buffer = realloc( buffer, size + (1000 * sizeof( long )) ))
== NULL )
{
free( oldbuffer ); // free original block
exit( 1 );
}
size = _msize( buffer );
printf( "Size of block after realloc of 1000 more longs: %u\n",
size );

free( buffer );
exit( 0 );
}

Output

Size of block after malloc of 1000 longs: 4000
Size of block after realloc of 1000 more longs: 8000

 

SetSize()分析

原代碼:

template< typename TYPE >
HRESULT CGrowableArray
<TYPE>::SetSize( int nNewMaxSize )
{
    
int nOldSize = m_nSize;

    
if( nOldSize > nNewMaxSize )
    {
        
// Removing elements. Call destructor.
        forint i = nNewMaxSize; i < nOldSize; ++i )
            m_pData[i].
~TYPE();
    }

    
// Adjust buffer.  Note that there's no need to check for error
    
// since if it happens, nOldSize == nNewMaxSize will be true.
    HRESULT hr = SetSizeInternal( nNewMaxSize );

    
if( nOldSize < nNewMaxSize )
    {
        
// Adding elements. Call constructor.
        forint i = nOldSize; i < nNewMaxSize; ++i )
            ::
new (&m_pData[i]) TYPE;
    }

    
return hr;
}

個人覺得這代碼寫的有些問題,作者說如果調(diào)用SetSizeInternal()失敗,則nOldSize == nNewMaxSize必成立,但實(shí)際上我們查看SetSizeInternal()的代碼發(fā)現(xiàn):

TYPE* pDataNew = (TYPE*) realloc( m_pData, nNewMaxSize * sizeof(TYPE) );
 if( pDataNew == NULL )
       return E_OUTOFMEMORY;

也就是說當(dāng)realloc()失敗的時候SetSizeInternal()調(diào)用會失敗,這時nOldSize為m_nSize,它不會恒等于nNewMaxSize,于是我將上面的代碼修改為:

template< typename TYPE >
HRESULT CGrowableArray
<TYPE>::SetSize( int nNewMaxSize )
{
    
int nOldSize = m_nSize;

    
if( nOldSize > nNewMaxSize )
    {
        
// Removing elements. Call destructor.
        forint i = nNewMaxSize; i < nOldSize; ++i )
            m_pData[i].
~TYPE();
    }

    
// Adjust buffer.  
    HRESULT hr = SetSizeInternal( nNewMaxSize );

    
if(FAILED(hr))
        
return hr;

    
if( nOldSize < nNewMaxSize )
    {
        
// Adding elements. Call constructor.
        forint i = nOldSize; i < nNewMaxSize; ++i )
            ::
new (&m_pData[i]) TYPE;
    }

    
return S_OK;
}

函數(shù)首先將原先內(nèi)存中的已賦值的元素個數(shù)保存為nOldSize,接下來的代碼:

    if( nOldSize > nNewMaxSize )
    {
        // Removing elements. Call destructor.
        for( int i = nNewMaxSize; i < nOldSize; ++i )
            m_pData[i].~TYPE();
    }

檢查新指定的內(nèi)存大小是否小于已分配內(nèi)存中已賦值元素的個數(shù),如果是則顯式調(diào)用各元素的析構(gòu)函數(shù)釋放資源,如下圖所示:


接著調(diào)用SetSizeInternal()重新分配大小,失敗則返回:

    // Adjust buffer.  
    HRESULT hr = SetSizeInternal( nNewMaxSize );

    if(FAILED(hr))
        return hr;

如果nNewMaxSize大于nOldSize,則調(diào)用構(gòu)造函數(shù)初始化元素的數(shù)據(jù),如下圖所示:


    if( nOldSize < nNewMaxSize )
    {
        // Adding elements. Call constructor.
        for( int i = nOldSize; i < nNewMaxSize; ++i )
            ::new (&m_pData[i]) TYPE;
    }

這里對顯式調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)做一些說明,之所以顯式調(diào)用,是因?yàn)閚ew沒有renew,而malloc和calloc有realloc,調(diào)用realloc可以避免頻繁調(diào)用malloc()和free()【或者new和delete】造成的性能損失,而realloc()不會自動調(diào)用構(gòu)造和析構(gòu)函數(shù),所以需要顯式調(diào)用。


Add()分析:

源碼:

template< typename TYPE >
HRESULT CGrowableArray
<TYPE>::Add( const TYPE& value )
{
    HRESULT hr;

    
if( FAILED( hr = SetSizeInternal( m_nSize + 1 ) ) )
        
return hr;

    
// Construct the new element
    ::new (&m_pData[m_nSize]) TYPE;
    
    m_pData[m_nSize] 
= value;
    
++m_nSize;

    
return S_OK;
}

代碼相當(dāng)明了,首先調(diào)用SetSizeInternal()分配大小,然后調(diào)用構(gòu)造函數(shù),給m_pData對應(yīng)位置的元素賦值,接著增加m_nSize的大小。
需要說明的是SetSizeInternal()并不會每調(diào)用一次Add()就重新分配內(nèi)存,只有當(dāng)指定的元素個數(shù)超過了m_nMaxSize的時候才會重新分配內(nèi)存。

 

Insert()分析:

template< typename TYPE >
HRESULT CGrowableArray
<TYPE>::Insert( int nIndex, const TYPE& value )
{
    HRESULT hr;

    
// Validate index
    if( nIndex < 0 || nIndex > m_nSize )
    {
        assert( 
false );
        
return E_INVALIDARG;
    }

    
// Prepare the buffer
    if( FAILED( hr = SetSizeInternal( m_nSize + 1 ) ) )
        
return hr;

    
// Shift the array
    MoveMemory( &m_pData[nIndex+1], &m_pData[nIndex], sizeof(TYPE) * (m_nSize - nIndex) );

    
// Construct the new element
    ::new (&m_pData[nIndex]) TYPE;

    
// Set the value and increase the size
    m_pData[nIndex] = value;
    
++m_nSize;

    
return S_OK;
}

Insert()在指定位置nIndex插入一個元素,函數(shù)通過MoveMemory()來移動內(nèi)存,它的定義如下:

#define MoveMemory RtlMoveMemory

#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length))

接著調(diào)用構(gòu)造函數(shù),賦值,增加m_nSize的大小。

 

SetAt():

template< typename TYPE >
HRESULT CGrowableArray
<TYPE>::SetAt( int nIndex, const TYPE& value )
{
    
// Validate arguments
    if( nIndex < 0 || nIndex >= m_nSize )
    {
        assert( 
false );
        
return E_INVALIDARG;
    }

    m_pData[nIndex] 
= value;
    
return S_OK;
}


IndexOf():
 
//--------------------------------------------------------------------------------------
// Searches for the specified value and returns the index of the first occurrence
// within the section of the data array that extends from iStart and contains the 
// specified number of elements. Returns -1 if value is not found within the given 
// section.
//--------------------------------------------------------------------------------------
template< typename TYPE >
int CGrowableArray<TYPE>::IndexOf( const TYPE& value, int iStart, int nNumElements )
{
    
// Validate arguments
    if( iStart < 0 || iStart >= m_nSize || nNumElements < 0 || iStart + nNumElements > m_nSize )
    {
        assert( 
false );
        
return -1;
    }

    
// Search
    forint i = iStart; i < (iStart + nNumElements); i++ )
    {
        
if( value == m_pData[i] )
            
return i;
    }

    
// Not found
    return -1;
}

 

LastIndexOf():

//--------------------------------------------------------------------------------------
// Searches for the specified value and returns the index of the last occurrence
// within the section of the data array that contains the specified number of elements
// and ends at iEnd. Returns -1 if value is not found within the given section.
//--------------------------------------------------------------------------------------
template< typename TYPE >
int CGrowableArray<TYPE>::LastIndexOf( const TYPE& value, int iEnd, int nNumElements )
{
    
// Validate arguments
    if( iEnd < 0 || iEnd >= m_nSize || nNumElements < 0 || iEnd - nNumElements < 0 )
    {
        assert( 
false );
        
return -1;
    }

    
// Search
    forint i = iEnd; i > (iEnd - nNumElements); i-- )
    {
        
if( value == m_pData[i] )
            
return i;
    }

    
// Not found
    return -1;
}

 

Remove():

template< typename TYPE >
HRESULT CGrowableArray
<TYPE>::Remove( int nIndex )
{
    
if( nIndex < 0 || nIndex >= m_nSize )
    {
        assert( 
false );
        
return E_INVALIDARG;
    }

    
// Destruct the element to be removed
    m_pData[nIndex].~TYPE();

    
// Compact the array and decrease the size
    MoveMemory( &m_pData[nIndex], &m_pData[nIndex+1], sizeof(TYPE) * (m_nSize - (nIndex+1)) );
    
--m_nSize;

    
return S_OK;
}

 

posted on 2008-05-18 14:05 lovedday 閱讀(2496) 評論(0)  編輯 收藏 引用 所屬分類: ■ DXUT Research

公告

導(dǎo)航

統(tǒng)計

常用鏈接

隨筆分類(178)

3D游戲編程相關(guān)鏈接

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美福利视频网站| 亚洲国产第一页| 久久久久久久网| 久久成人精品一区二区三区| 亚洲欧美日韩国产另类专区| 亚洲欧美激情四射在线日| 午夜久久久久久| 久久先锋影音| 欧美日韩国产亚洲一区| 国产精品久久久久久超碰 | 国产乱码精品一区二区三| 国产精品一二一区| 在线观看91精品国产入口| 日韩一二三区视频| 欧美一区二区三区男人的天堂 | 性久久久久久久久久久久| 久久99伊人| 亚洲国产一区二区三区a毛片| 亚洲人午夜精品| 午夜精品影院在线观看| 欧美11—12娇小xxxx| 国产精品一香蕉国产线看观看| 在线观看欧美| 亚洲综合精品| 亚洲丶国产丶欧美一区二区三区 | 国产欧美一区二区精品婷婷| 亚洲夫妻自拍| 午夜久久电影网| 亚洲国产精品精华液2区45| 亚洲欧美日韩电影| 欧美日韩国产首页| 在线观看成人av电影| 亚洲欧美国产精品va在线观看| 欧美成人一区二区三区| 亚洲欧美日韩精品一区二区 | 欧美激情1区| 国产真实乱子伦精品视频| 一道本一区二区| 欧美成人免费全部| 欧美一区二区视频在线观看| 免费国产自线拍一欧美视频| 亚洲一区二区av电影| 农村妇女精品| 在线观看视频一区| 欧美呦呦网站| 日韩视频在线观看一区二区| 欧美成人性网| 亚洲国产精品第一区二区| 欧美在线www| 亚洲视频在线观看一区| 欧美理论在线播放| 亚洲日本一区二区三区| 美乳少妇欧美精品| 久久成人一区二区| 国产一本一道久久香蕉| 欧美一区二区三区婷婷月色| 一本一道久久综合狠狠老精东影业| 欧美成人性网| 99这里有精品| 亚洲最新视频在线播放| 欧美日韩一区二区免费视频| 亚洲精品三级| 99国产精品久久久久老师| 欧美三级午夜理伦三级中视频| 99视频一区| 99精品热6080yy久久| 国产精品户外野外| 久久成人免费网| 久久久国产精品一区二区三区| 狠狠色丁香久久婷婷综合_中| 久久色在线播放| 欧美不卡视频| 在线亚洲一区二区| 亚洲一区国产| 国产午夜一区二区三区| 久久综合九色综合欧美就去吻| 久久久精品网| 亚洲免费av网站| 一区二区三区|亚洲午夜| 国产欧美视频在线观看| 女女同性精品视频| 欧美精品久久天天躁 | 久久9热精品视频| 久久免费99精品久久久久久| 最近看过的日韩成人| 9久re热视频在线精品| 国产一区二区久久久| 欧美不卡视频| 国产精品久久一卡二卡| 免费一级欧美在线大片| 欧美日韩你懂的| 久久久久久一区| 欧美日本一区二区视频在线观看| 午夜精品短视频| 米奇777超碰欧美日韩亚洲| 亚洲深夜福利网站| 久久久久久尹人网香蕉| 亚洲一区高清| 欧美国产日本在线| 久久激情久久| 91久久国产综合久久| 精品1区2区3区4区| 欧美顶级少妇做爰| 久久福利毛片| 亚洲深夜福利| 亚洲黄网站在线观看| 欧美一区二区在线看| 亚洲精品一区二区三区四区高清| 国产精品一级在线| 欧美午夜激情视频| 欧美性jizz18性欧美| 欧美经典一区二区| 麻豆国产va免费精品高清在线| 亚洲欧美在线一区二区| 亚洲一区二区在线免费观看| 亚洲精品五月天| 99热在线精品观看| 国产精品99久久久久久久久久久久| 99视频超级精品| 亚洲一区精品视频| 欧美一区二区三区视频在线观看 | 久久精品国产精品| 欧美一区二区三区四区高清| 亚洲欧美在线网| 久久久精彩视频| 欧美阿v一级看视频| 亚洲精品免费电影| 亚洲欧美国产视频| 免费成人av资源网| 欧美日韩国产专区| 国产农村妇女精品| 亚洲国产欧美一区二区三区久久 | 亚洲成人在线视频播放 | 欧美成人精品在线视频| 欧美精品久久一区| 国产欧美日韩在线视频| 亚洲国产日本| 欧美一区二区视频在线| 欧美激情一区二区三区四区 | 亚洲国产mv| 亚洲在线免费观看| 欧美激情一级片一区二区| 国产精品日韩在线观看| 亚洲精品国产品国语在线app| 亚洲欧美在线网| 亚洲精品在线免费| 久久成人一区| 国内精品久久久久影院 日本资源| 日韩午夜在线观看视频| 你懂的亚洲视频| 欧美大成色www永久网站婷| 国产亚洲一区二区精品| 亚洲综合三区| 亚洲一区在线免费| 国产精品中文在线| 午夜精品久久久久久久99水蜜桃| 99爱精品视频| 国产一区二区三区最好精华液| 亚洲宅男天堂在线观看无病毒| 日韩视频在线一区二区三区| 欧美精品国产精品日韩精品| 一区二区三区 在线观看视频| 亚洲美女尤物影院| 国产精品分类| 毛片一区二区三区| 欧美成人精品| 久久大逼视频| 久久中文欧美| 欧美黄色aaaa| 久久国产精品久久国产精品| 久久久999精品| 中文av字幕一区| 久久精品国产第一区二区三区最新章节 | 欧美日韩大片一区二区三区| 亚洲欧美怡红院| 欧美福利一区二区三区| 亚洲欧美日韩天堂一区二区| 久久久精品动漫| 亚洲欧美在线视频观看| 欧美激情一区二区在线| 久久久精品tv| 国产欧美精品一区二区色综合| 欧美激情一区二区久久久| 国产亚洲欧美激情| 亚洲精品国产精品国产自| 狠狠v欧美v日韩v亚洲ⅴ| 亚洲一区日韩在线| 亚洲视频在线一区观看| 欧美黄色片免费观看| 欧美成年人视频网站欧美| 国产女人18毛片水18精品| 亚洲午夜小视频| 日韩一区二区电影网| 欧美激情一区二区三区成人| 免费成人在线观看视频| 一区二区三区在线免费观看| 久久成人精品视频| 久热精品视频在线观看一区| 国内外成人免费视频| 久久岛国电影|