• <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>

            szwolf

            專(zhuān)注于C++技術(shù),再用1年的時(shí)間努力學(xué)C++!
            隨筆 - 2, 文章 - 0, 評(píng)論 - 2, 引用 - 0
            數(shù)據(jù)加載中……

            STL學(xué)習(xí)之一:構(gòu)建自己的內(nèi)存配置器

            ???使用STL已經(jīng)有一段時(shí)間了,對(duì)里面的運(yùn)作方式一直不了解。這幾天突發(fā)其想,找了一些關(guān)于STL源碼的書(shū)看了一下,覺(jué)得其內(nèi)部實(shí)現(xiàn)非常精妙。作為進(jìn)一步學(xué)習(xí),我打算把STL中的主要組件自己動(dòng)手實(shí)現(xiàn)一下。
            ???首先從空間配置器開(kāi)始,從內(nèi)部逐漸了解STL中各種容器的實(shí)現(xiàn)細(xì)節(jié)。
            ???根據(jù)STL的規(guī)范,allocator必須有以下接口:
            ???

            typedef????size_t????????size_type;
            typedef????T????????value_type;
            typedef????T
            * ????????pointer;
            typedef????ptrdiff_t????difference_type;
            typedef????
            const ?T * ????const_pointer;
            typedef????T
            & ????????reference;
            typedef????
            const ?T & ????const_reference;

            rebind
            allocator(
            const ?allocator < U >& ?)
            ~ allocator()?
            pointer?address(reference?x)
            const_pointer?address(const_pointer?x)
            T
            * ?allocate(size_type?n,? void * ?p? = ? 0 )
            void ?deallocate(pointer?p,?size_type?n)
            size_type?max_size()
            void ?construct(pointer?p,?const_reference?val)
            void ?destroy(pointer?p)

            ?SGI STL并沒(méi)有按C++ STD的說(shuō)沒(méi)直接做一個(gè)Allocator出來(lái),而是先做出兩個(gè)Allocator template及以內(nèi)存池的形式來(lái)構(gòu)?//造Allocator比STD::allocator效率更高且減少了內(nèi)存碎片。下面是sgi_allocator.h的代碼:

            #ifndef?SGI_ALLOCATOR
            #define ?SGI_ALLOCATOR
            #include?
            < iostream >
            #include?
            < cstddef > ???????? // for?size_t
            using ? namespace ?std;

            namespace ?SGI
            {
            ????template < int ?inst >
            ????
            class ?malloc_alloc_template???? // 一級(jí)空間配置器
            ???? {
            ????
            public :
            ????????
            static ? void * ?allocate(size_t?n)
            ????????
            {
            ????????????
            void * ?result? = ?malloc(n);
            ????????????
            if ?(result? == ?NULL)
            ????????????
            {
            ????????????????result?
            = ?oom_malloc(n);???????? // 內(nèi)存不足調(diào)用oom_malloc()進(jìn)行處理
            ????????????}


            ????????????
            return ?result;
            ????????}


            ????????
            static ? void ?deallocate( void * ?p,?size_t)???? // 第二個(gè)參數(shù)無(wú)所謂,只要一進(jìn)來(lái)就把它干掉..
            ???????? {
            ????????????free(p);
            ????????}


            ????????
            static ? void * ?reallocate( void * ?p,?size_t /* old?size */ ,?size_t?new_size)
            ????????
            {
            ????????????
            void * ?result? = ?realloc(p,?new_size);
            ????????????
            if (result? == ?NULL)
            ????????????
            {
            ????????????????result?
            = ?oom_realloc(p,?new_size);
            ????????????}


            ????????????
            return ?result;
            ????????}


            ????????
            static ? void ?( * set_malloc_handler( void ?( * f)()))()
            ????????
            {
            ????????????
            void ?( * old)()? = ?oom_malloc_handler;
            ????????????oom_malloc_handler?
            = ?f;

            ????????????
            return ?old;
            ????????}

            ????
            private :
            ????????
            static ? void * ?oom_malloc(size_t);???????? // 內(nèi)存不足時(shí)調(diào)用這個(gè)函數(shù)(因?yàn)槔锩嬗刑幚砗瘮?shù))
            ???????? static ? void * ?oom_realloc( void * ,?size_t); // 同上
            ???????? static ? void ?( * oom_malloc_handler)();???? // 內(nèi)存不足時(shí)的處理函數(shù)
            ????}
            ;
            ????template
            < int ?inst >
            ????
            void * ?malloc_alloc_template < inst > ::oom_malloc(size_t?size)
            ????
            {
            ????????
            void * ?result;
            ????????
            ????????
            while ( true )???????????? // 反得調(diào)用處理函數(shù),直到申請(qǐng)成功.如果沒(méi)有定義處理函數(shù)則拋出異常
            ???????? {
            ????????????
            if ?(oom_malloc_handler? == ?NULL)
            ????????????
            {
            ????????????????
            throw ?bad_alloc();
            ????????????}

            ????????????(
            * oom_malloc_handler)();
            ????????????
            if ?(?(result? = ?malloc(size))? != ?NULL)
            ????????????
            {
            ????????????????
            return ?result;
            ????????????}

            ????????}

            ????}


            ????template
            < int ?inst >
            ????
            void * ?malloc_alloc_template < inst > ::oom_realloc( void * ?p,?size_t?new_size)
            ????
            {
            ????????
            void * ?result;

            ????????
            while ( true )
            ????????
            {
            ????????????
            if ?(oom_malloc_handler? == ?NULl)
            ????????????
            {
            ????????????????
            throw ?bad_alloc();
            ????????????}

            ????????????(
            * oom_alloc_handler)();
            ????????????
            if ?(?(result? = ?realloc(p,?new_size))? != ?NULL)
            ????????????
            {
            ????????????????
            return ?result;
            ????????????}

            ????????}

            ????}


            ????template
            < int ?inst >
            ????
            void ?( * malloc_alloc_template < inst > ::oom_malloc_handler)()? = ?NULL;

            ????typedef?malloc_alloc_template
            < 0 > ?malloc_alloc;???????? // 到此完成一級(jí)空間配置器的定義

            ????
            //////////////////////////////////////////////////////
            ???? // 下面是對(duì)一二級(jí)配置器的封裝,?其中Alloc即為空間配置器
            ????
            // 默認(rèn)用的是二級(jí)配置器,當(dāng)>128K或內(nèi)存不足時(shí)會(huì)交給一級(jí)
            ????
            // 配置器處理
            ???? /////////////////////////////////////////////////// //j?
            ????template < typename?T,?typename?Alloc > ????????????
            ????
            class ?simple_alloc
            ????
            {
            ????
            public :
            ????????
            static ?T * ?allocate(size_t?n)
            ????????
            {
            ????????????
            return ?n? == ? 0 ? ? ? 0 ?:?(T * )Alloc::allocate(n? * ? sizeof (T));
            ????????}


            ????????
            static ?T * ?allocate()
            ????????
            {
            ????????????
            return ?(T * )Alloc::allocate( sizeof (T));
            ????????}


            ????????
            static ? void ?deallocate(T * ?p,?size_t?n)
            ????????
            {
            ????????????
            if ?(n? != ? 0 )
            ????????????
            {
            ????????????????Alloc::deallocate(p,?n?
            * ? sizeof (T));???????? // 這里要用兩個(gè)參數(shù)是為了與后面的二級(jí)配置器配合(這個(gè)問(wèn)題郁悶了我好久,呵呵,菜啊!)
            ????????????}

            ????????}


            ????????
            static ? void ?deallocate(T * ?p)
            ????????
            {
            ????????????Alloc::deallocate(p,?
            sizeof (T));
            ????????}

            ????}
            ;

            ????
            enum {ALIGN? = ? 8 ,?MAX_BYTES? = ? 128 ,?NFREELISTS? = ? 16 } ;???? // ?其中NFREELISTS?=?MAX_BYTES?/?ALIGN
            ????
            ????template
            < bool ?threads,? int ?inst >
            ????
            class ?default_alloc_template???? // 定義二級(jí)配置器
            ???? {
            ????
            public :
            ????????
            static ? void * ?allocate(size_t?n)
            ????????
            {
            ????????????
            void * ?result;
            ????????????
            ????????????
            if ?(n? > ?(size_t)MAX_BYTES)
            ????????????
            {
            ????????????????result?
            = ?malloc_alloc::allocate(n);???????? // >128K交給一級(jí)配置器處理
            ????????????}

            ????????????
            else
            ????????????
            {
            ????????????????Obj
            * ? volatile * ?my_free_list???? = ?free_list? + ?free_list_index(n);
            ????????????????
            if ?(?(result? = ? * my_free_list)? == ?NULL)
            ????????????????
            {
            ????????????????????result????
            = ????refill(round_up(n));
            ????????????????}

            ????????????????
            else
            ????????????????
            {
            ????????????????????Obj
            * ?tmp???????? = ? * my_free_list;
            ????????????????????
            * my_free_list???? = ?tmp -> free_list_link;
            ????????????????????result????????????
            = ?tmp;
            ????????????????}

            ????????????}


            ????????????
            return ?result;
            ????????}


            ????????
            static ? void ?deallocate( void * ?p,?size_t?n)
            ????????
            {
            ????????????
            if ?(n? > ?(size_t)MAX_BYTES)
            ????????????
            {
            ????????????????malloc_alloc::deallocate(p,?n);
            ????????????}

            ????????????
            else
            ????????????
            {
            ????????????????Obj
            * ? volatile * ?my_free_list? = ?free_list? + ?free_list_index(n);
            ????????????????Obj
            * ?q? = ?(Obj * )?p;
            ????????????????q
            -> free_list_link???? = ? * my_free_list;
            ????????????????
            * my_free_list???????? = ?q;
            ????????????}

            ????????}


            ????????
            static ? void * ?reallocate( void * ?p,?size_t?old_size,?size_t?new_ize);

            ????
            private :
            ????????
            static ?size_t?round_up(size_t?bytes)
            ????????
            {
            ????????????
            return ?((bytes? + ?(size_t)ALIGN? - ? 1 )? & ? ~ ((size_t)ALIGN? - ? 1 ));
            ????????}

            ????????
            ????????union?Obj????????????
            // Trick,既可以作指針,又可以作為內(nèi)存地址
            ???????? {
            ????????????union?Obj
            * ?free_list_link;
            ????????????
            char ?client_data[ 1 ];
            ????????}
            ;

            ????????
            static ?Obj * ? volatile ?free_list[NFREELISTS];

            ????????
            static ?size_t?free_list_index(size_t?size)
            ????????
            {
            ????????????
            return ?((size? + ?(size_t)ALIGN? - ? 1 )? / ?(size_t)ALIGN? - 1 );
            ????????}

            ????????
            ????????
            static ? void * ?refill(size_t?n);
            ????????
            static ? char * ?chunk_alloc(size_t?size,?size_t & ?objs);
            ????????
            ????????
            static ? char * ????chunk_start;???? // 內(nèi)存池起始位置
            ???????? static ? char * ????chunk_end;???????? // 內(nèi)存池結(jié)束位置
            ???????? static ?size_t????heap_size;???????? // 從開(kāi)始至今在堆中申請(qǐng)的字節(jié)總數(shù)

            ????}
            ;

            ????template
            < bool ?threads,? int ?inst >
            ????
            char * ?default_alloc_template < threads,?inst > ::chunk_start? = ?NULL;

            ????template
            < bool ?threads,? int ?inst >
            ????
            char * ?default_alloc_template < threads,?inst > ::chunk_end? = ?NULL;

            ????template
            < bool ?threads,? int ?inst >
            ????size_t?default_alloc_template
            < threads,?inst > ::heap_size? = ? 0 ;
            ????
            ????template
            < bool ?threads,? int ?inst >
            ????typename?default_alloc_template
            < threads,?inst > ::Obj * ? volatile ?default_alloc_template < threads,?inst > ::free_list[NFREELISTS]? = ? { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;


            ????
            // 核心部分,從內(nèi)存池中申請(qǐng)空間
            ????template < bool ?threads,? int ?inst >
            ????
            char * ?default_alloc_template < threads,?inst > ::chunk_alloc(size_t?size,?size_t & ?nobjs)
            ????
            {
            ????????
            char * ????result???????? = ?NULL;
            ????????size_t????total_bytes????
            = ?size? * ?nobjs;????????????????????????
            ????????size_t????bytes_left????
            = ?chunk_end? - ?chunk_start;???????????? // 內(nèi)存池所剩水量

            ????????
            if ?(?bytes_left? > ?total_bytes)???????????????????????????? // 內(nèi)存池中有足夠空間可以分配
            ???????? {
            ????????????result????????
            = ????chunk_start;
            ????????????chunk_start?
            += ????total_bytes;

            ????????????
            return ?result;
            ????????}

            ????????
            else ? if (bytes_left? >= ?size)???????????????????????? // 內(nèi)存池中空間至少可以分配一個(gè)塊
            ???????? {
            ????????????nobjs????????????
            = ????( int )bytes_left? / ?size;
            ????????????total_bytes????????
            = ????size? * ?nobjs;
            ????????????result????????????
            = ????chunk_start;
            ????????????chunk_start????
            += ????total_bytes;

            ????????????
            return ?result;
            ????????}

            ????????
            else ???????????????????????????????????????? // 內(nèi)存池已山窮水盡一個(gè)塊都無(wú)法分配出來(lái)?T_T
            ???????? {
            ????????????size_t?bytes_to_get????
            = ?total_bytes? + ?round_up(heap_size? >> ? 4 );???????? // 申請(qǐng)總數(shù)兩位加上擴(kuò)展

            ????????????
            if ?(bytes_left? > ? 0 )
            ????????????
            {
            ????????????????Obj
            * ? volatile * ?my_free_list???????????? = ?free_list? + ?free_list_index(bytes_left);
            ????????????????((Obj
            * )chunk_start) -> free_list_link???? = ? * my_free_list;
            ????????????????
            * my_free_list???????????????????????? = ?(Obj * )chunk_start;
            ????????????}

            ????????????chunk_start????
            = ????( char * )malloc(bytes_to_get);
            ????????????
            if ?(chunk_start? == ?NULL)???????? // 內(nèi)存不足這下麻煩了,看看表中有沒(méi)有空間可以回收
            ???????????? {
            ????????????????Obj
            * ? volatile * ?my_free_list;
            ????????????????Obj
            * ?p;

            ????????????????
            for (size_t?i? = ?size;?i? <= ?MAX_BYTES;?i? += ?ALIGN)
            ????????????????
            {
            ????????????????????my_free_list????
            = ????free_list? + ?free_list_index(i);
            ????????????????????p????????????????
            = ???? * my_free_list;

            ????????????????????
            if ?(p? != ?NULL)???? // 找到適合的空間,進(jìn)行回收
            ???????????????????? {????????????????????????
            ????????????????????????
            * my_free_list???? = ????p -> free_list_link;
            ????????????????????????chunk_start????????
            = ????( char * )p;
            ????????????????????????chunk_end????????
            += ????i;

            ????????????????????????
            return ?chunk_alloc(size,?nobjs);

            ????????????????????}

            ????????????????}

            ????????????????
            ????????????????
            // 完全走投無(wú)路了,只好看看內(nèi)存不足的處理函數(shù)能不能幫上忙
            ????????????????chunk_end???? = ????NULL;
            ????????????????chunk_start????
            = ????( char * )malloc_alloc::allocate(bytes_to_get);
            ????????????}

            ????????????chunk_end????
            += ????bytes_to_get;
            ????????????heap_size????
            += ????bytes_to_get;

            ????????????
            return ?chunk_alloc(size,?nobjs);
            ????????}

            ????}


            ????
            /*
            ?????*?返回一個(gè)大小為n的塊,?并且可能適當(dāng)?shù)貫閒ree_list增加節(jié)點(diǎn)
            ?????*
            ?????
            */

            ????template
            < bool ?threads,? int ?inst >
            ????
            void * ?default_alloc_template < threads,?inst > ::refill(size_t?n)
            ????
            {
            ????????size_t????????nobjs?
            = ? 20 ;???????????????? // 默認(rèn)申請(qǐng)塊的個(gè)數(shù)
            ????????Obj * ????????curr;
            ????????Obj
            * ????????next;
            ????????

            ????????
            char * ????result? = ?chunk_alloc(n,?nobjs);
            ????????
            if ?(nobjs? == ? 1 )???????? // 只申請(qǐng)到一塊空間則直接返回給調(diào)用者
            ???????? {
            ????????????
            return ?result;
            ????????}

            ????????
            else ???????????? // 申請(qǐng)到多于一個(gè)塊,將其它nobjs?-?1個(gè)塊加到free_list中?:?)
            ???????? {
            ????????????Obj
            * ? volatile * ?my_free_list???? = ?free_list? + ?free_list_index(n);;
            ????????????
            * my_free_list? = ?next? = ?(Obj * )(result? + ?n);
            ????????????
            for ( int ?i? = ? 1 ;?;? ++ i)
            ????????????
            {????????????????
            ????????????????curr????
            = ????next;
            ????????????????next????
            = ?(Obj * )(?( char * )next? + ?n);

            ????????????????
            if ?(i? == ?nobjs? - ? 1 )
            ????????????????
            {
            ????????????????????curr
            -> free_list_link???? = ????NULL;
            ????????????????????
            break ;
            ????????????????}

            ????????????????
            else
            ????????????????
            {
            ????????????????????curr
            -> free_list_link???? = ????next;
            ????????????????}

            ????????????}

            ????????????
            return ?result;
            ????????}

            ????}


            ????template
            < bool ?threads,? int ?inst >
            ????
            static ? void * ?default_alloc_template < threads,?inst > ::reallocate( void * ?p,?size_t?old_size,?size_t?new_size)
            ????
            {
            ????????
            if ?(old_size? > ?MAX_BYTES? && ?new_size? > ?MAX_BYTES)
            ????????
            {
            ????????????
            return ?realloc(p,?new_size);
            ????????}


            ????????
            if ?(round_up(old_size)? == ?round_up(new_size))
            ????????
            {
            ????????????
            return ?p;
            ????????}


            ????????
            void * ?result? = ?malloc(new_size);
            ????????
            int ?copy_size? = ?new_size? > ?old_size? ? ?old_size?:?new_size;
            ????????memcpy(result,?p,?copy_size);

            ????????
            return ?result;
            ????}

            ????
            ????typedef?default_alloc_template
            < false ,? 0 > ?alloc;

            ????
            /*
            ?????*?對(duì)以定義好的兩個(gè)配置器模板進(jìn)行封裝,以使其與STL相容
            ?????
            */

            ????template
            < typename?T >
            ????
            class ?allocator
            ????
            {
            ????
            public :
            ????????typedef????????size_t????????size_type;
            ????????typedef????????T????????????value_type;
            ????????typedef????????T
            * ????????????pointer;
            ????????typedef????????ptrdiff_t????difference_type;
            ????????typedef????????
            const ?T * ????const_pointer;
            ????????typedef????????T
            & ????????????reference;
            ????????typedef????????
            const ?T & ????const_reference;

            ????????template
            < typename?U > ?
            ????????
            struct ?rebind
            ????????
            {
            ????????????typedef?allocator
            < U > ?other;
            ????????}
            ;

            ????????allocator()?
            throw ()
            ????????
            {
            ????????}


            ????????template
            < typename?U >
            ????????allocator(
            const ?allocator < U >& ?)? throw ()
            ????????
            {
            ????????}

            ????????
            ????????
            ~ allocator()? throw ()
            ????????
            {
            ????????}


            ????????pointer?address(reference?x)?
            const
            ????????
            {
            ????????????
            return ? & ?x;
            ????????}


            ????????const_pointer?address(const_pointer?x)?
            const
            ????????
            {
            ????????????
            return ? & x;
            ????????}


            ????????T
            * ?allocate(size_type?n,? void * ?p? = ? 0 )
            ????????
            {
            ????????????
            return ?n? != ? 0 ? ? ?static_cast < T *> (alloc::allocate(n? * ? sizeof (T)))?:? 0 ;
            ????????}


            ????????
            void ?deallocate(pointer?p,?size_type?n)
            ????????
            {
            ????????????alloc::deallocate(p,?n
            * sizeof (T));
            ????????}


            ????????size_type?max_size()?
            const ? throw ()
            ????????
            {
            ????????????
            return ?(size_t) - 1 / sizeof (T);
            ????????}


            ????????
            void ?construct(pointer?p,?const_reference?val)
            ????????
            {
            ????????????
            new (p)T(val);
            ????????}


            ????????
            void ?destroy(pointer?p)
            ????????
            {
            ????????????p
            ->~ T();
            ????????}
            ????????
            ????}
            ;

            }


            #endif

            ?以下是測(cè)試文件,現(xiàn)在比較晚了。。沒(méi)有寫(xiě)一個(gè)比較像樣的測(cè)試,以后有時(shí)候再寫(xiě)寫(xiě)。。。

            // ?sgi_allocator.cpp?:?定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
            //
            /*
            ?*????模擬SGI?STL中allocator的實(shí)現(xiàn),以內(nèi)存池的形式,構(gòu)建一個(gè)比STD::allocator
            ?*????更高效的空間配置器
            ?*????作者:?Szwolf
            ?*????2006.8.3:23.31'暑假@SZU
            ?*
            ?
            */

            #include?
            " stdafx.h "
            #include?
            " sgi_allocator.h "
            #include?
            < iostream >
            #include?
            < vector >
            #include?
            < algorithm >

            using ? namespace ?std;

            class ?test
            {
            public :
            ????friend?ostream
            & ? operator ? << ?(ostream & ?os,? const ?test & ?x)
            ????
            {
            ????????
            return ?os? << ? " test?success?:?) " ? << ?endl;
            ????}

            }
            ;

            int ?_tmain( int ?argc,?_TCHAR * ?argv[])
            {
            ????
            int ?a[]? = ? { 1 , 2 , 3 , 4 } ;
            ????test?b[
            10 ];
            ????vector
            < int ,?SGI::allocator < int > ? > ?vec(a,?a? + ? 4 );
            ????vector
            < test,?SGI::allocator < test > ? > vec2(b,?b + 10 );
            ????copy(vec.begin(),?vec.end(),?ostream_iterator
            < int > (cout,? " ? " ));
            ????cout?
            << ?endl;
            ????copy(vec2.begin(),?vec2.end(),?ostream_iterator
            < test > (cout));
            ????cout?
            << ?endl;

            ????
            return ? 0 ;
            }

            一個(gè)類(lèi)似于SGI STL::allocator的空間配置器就這樣完成了:)個(gè)人感覺(jué)在建內(nèi)存池的過(guò)程從其無(wú)所不用其極的空間申請(qǐng)方式中受益頗多~~~(呵呵,鏈表操作又復(fù)習(xí)了一遍。。)
            ?以下是在VS2005中可以正常編譯通過(guò)的源碼:
            http://www.shnenglu.com/Files/szwolf/sgi_allocator.rar

            posted on 2006-08-06 01:15 szwolf 閱讀(1311) 評(píng)論(2)  編輯 收藏 引用

            評(píng)論

            # re: STL學(xué)習(xí)之一:構(gòu)建自己的內(nèi)存配置器  回復(fù)  更多評(píng)論   

            老大,既然你開(kāi)博,并且貼出代碼,就貼全,干嘛臨代碼結(jié)束了,漏掉一句,呵呵,不要告訴我是故意的喔!:-)

            謝謝你將stl的代碼清晰化,并且加了注釋?zhuān)喿x更方便了,謝謝!
            2008-12-30 11:23 | mislang

            # re: STL學(xué)習(xí)之一:構(gòu)建自己的內(nèi)存配置器  回復(fù)  更多評(píng)論   

            大哥:對(duì)不起了!剛剛仔細(xì)看了代碼,建議您還是把代碼撤下來(lái)吧,太多錯(cuò)誤!
            哎。。。

            質(zhì)量!

            為了不給后來(lái)人添亂,您還是撤了吧,謝謝!
            2008-12-30 17:46 | mislang

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久综合精品国产一区二区三区| 亚洲国产精品综合久久网络| 狠狠色狠狠色综合久久| 国内精品伊人久久久久av一坑| 久久噜噜电影你懂的| 一本色道久久综合| 久久中文娱乐网| 精品人妻伦九区久久AAA片69| 人人妻久久人人澡人人爽人人精品 | 国产成人精品久久亚洲高清不卡 | 国产精品成人久久久久三级午夜电影| 亚洲国产精品久久久久久| 午夜精品久久久久久久| 91麻豆国产精品91久久久| 国产成人久久AV免费| 久久久久女教师免费一区| 亚洲乱亚洲乱淫久久| 国产A级毛片久久久精品毛片| 亚洲综合婷婷久久| 亚洲va中文字幕无码久久| 日日狠狠久久偷偷色综合0| 亚洲国产成人久久综合碰碰动漫3d | 国产精品久久久久jk制服| 日本久久中文字幕| 丁香久久婷婷国产午夜视频| 久久青青草原亚洲av无码app| 久久精品国产99国产精品导航| 久久影院亚洲一区| 精品免费tv久久久久久久| 麻豆精品久久精品色综合| 欧美国产成人久久精品| 欧洲性大片xxxxx久久久| 精品99久久aaa一级毛片| 国产精品久久久久久搜索| 久久91精品国产91久久户| 久久久久无码精品国产| 亚洲AV无码久久精品蜜桃| 精产国品久久一二三产区区别| 久久综合伊人77777麻豆| 欧美与黑人午夜性猛交久久久| 久久99精品国产99久久6|