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

隨筆-91  評論-137  文章-0  trackbacks-0

QCore/Library說明文檔

李文超

前言

 

QCore/Library是一套類STL的類庫,它在標準庫的范圍內刪去了不常用的heap、deque等結構(至少我是不常用的)。并為一些容器提供了一些特殊的接口,比如vector中的push_back_unique、add和add_unique等。

 

Library主要分為六部分,內存調試相關、容器、算法、正則、IO和Graphic,每個模塊都有各自的分工,他們之間的耦合度極低,幾乎每個模塊都可以拆出來獨立使用,下面來分別介紹各個模塊。

內存調試

 

我們知道,在C/C++中內存相關的東西是極難控制的,在使用不當時可能造成各種錯誤,輕則內存泄漏,重則程序崩潰。所以,在生產環境中我們必須通過一個有效的手段來管理好內存。當然,在小塊內存頻繁new、delete的過程中也會產生大量的內存碎片,從而導致可用內存數量越來越少。應此我們設計了一個內存池來控制小塊內存的頻繁new、delete,以及做到對內存泄漏的檢測。

 

在內存池的設計之初,我只是簡單的設計出了可以使用的MemoryPool的最簡版本,它包含一個大塊內存的free_list和每個小塊內存的chunk_list,當時足以應付大部分的需求,而且最初用的是Visual Leak Detector來檢測內存泄漏。但隨著時間的推移,想要自己檢測內存泄漏的欲望越來越強烈,之后便有了一個use_list來保存內存塊的釋放情況。當時完成了這個patch之后,興奮的跑了一下TestCase,然后的結果我想大家應該知道了,一路的飄紅,到處是內存泄漏。

 

經過一天的調試,實在無法容忍的情況下,我翻閱了MSDN,查到了dbghelp.dll中可以通過許多函數來獲取調用堆棧,于是在此之下便生產出了CallStack模塊。有了它之后你就可以在任意地方保存當前的調用堆棧了,真是十分方便。當然直到現在,它還只支持在Windows下調用堆棧的獲?。ㄉ院笪視嗁Y料,實現一個like unix的版本,如果可能的話)。

 

這里不過多的描述實現的細節,具體可以看http://www.shnenglu.com/lwch/archive/2012/07/14/183420.htmlhttp://www.shnenglu.com/lwch/archive/2013/01/19/197415.html兩篇文章。

 

最后來看allocator,這里只是簡單的為其包裝了一層。

 

template <typename T>

class allocator

{

public:

    allocator()

    {

    }

 

    allocator(const allocator<T>&)

    {

    }

 

    static T* allocate()

    {

        MemoryPool* pool = getPool();

        return reinterpret_cast<T*>(pool->allocate(sizeof(T), free_handler));

    }

 

    static T* allocate(size_t n)

    {

        MemoryPool* pool = getPool();

        return reinterpret_cast<T*>(pool->allocate(n * sizeof(T), free_handler));

    }

 

    static void deallocate(T* p)

    {

        MemoryPool* pool = getPool();

        pool->deallocate(p, sizeof(T));

    }

 

    static void deallocate(T* p, size_t n)

    {

        MemoryPool* pool = getPool();

        pool->deallocate(p, n * sizeof(T));

    }

 

    static void deallocateWithSize(T* p, size_t n)

    {

        MemoryPool* pool = getPool();

        pool->deallocate(p, n);

    }

 

    static T* reallocate(T* p, size_t old_size, size_t n)

    {

        MemoryPool* pool = getPool();

        return pool->reallocate(p, old_size, n * sizeof(T), free_handler);

    }

public:

    static void(*free_handler)(size_t);

 

    static void set_handler(void(*h)(size_t))

    {

        free_handler = h;

    }

protected:

    static MemoryPool* getPool()

    {

        static MemoryPool pool;

        return &pool;

    }

};

 

template <typename T>

void (*allocator<T>::free_handler)(size_t) = 0;

容器

 

容器占了Library的大部分,容器的作用是用來存儲對象的,容器分為線性和非線性兩種。線性的容器有vector、list、string以及用它們作為容器實現的queue、stack四種,非線性的則有rbtree、hashtable以及用它們作為容器實現的set、map、hashset、hashmap六種。對于每種容器,都必須定義出它的value_type、pointer、reference、const_reference、size_type、distance_type、const_iterator、const_reverse_iterator、iterator、reverse_iterator的類型。

 

所有容器必須包含以下幾個接口:size(獲取容器內元素個數)、clear(清空容器)、begin(獲取[first,last)區間中的first迭代器)、end(獲取[first,last)區間中的last迭代器)、rbegin(獲取反向的first迭代器)、rend(獲取反向的last迭代器)。

traits

 

traits是一種萃取技術,通過它你可以獲取某種類型的一些特性,比如是否含有默認構造函數、拷貝構造函數等。

__type_traits

 

__type_traits用于萃取出某種類型的一些特性,它的原型如下

 

template <typename T>

struct __type_traits

{

    typedef __true_type has_default_construct;

    typedef __true_type has_copy_construct;

    typedef __true_type has_assign_operator;

    typedef __true_type has_destruct;

    typedef __false_type is_POD;

};

通過特例化,可以定義出所有類型的這些屬性,比如char

 

template <>

struct __type_traits<char>

{

    typedef __true_type has_default_construct;

    typedef __true_type has_copy_construct;

    typedef __true_type has_assign_operator;

    typedef __false_type has_destruct;

    typedef __true_type is_POD;

};

__container_traits

 

__container_traits用于萃取出容器的特性,如上文所說的value_type等特性,它的代碼很簡單

 

template <typename T>

struct __container_traits

{

    typedef typename T::value_type value_type;

    typedef typename T::pointer pointer;

    typedef typename T::reference reference;

    typedef typename T::const_reference const_reference;

    typedef typename T::size_type size_type;

    typedef typename T::distance_type distance_type;

    typedef typename T::const_iterator const_iterator;

    typedef typename T::const_reverse_iterator const_reverse_iterator;

    typedef typename T::iterator iterator;

    typedef typename T::reverse_iterator reverse_iterator;

};

char_traits

 

char_traits定義了一些對于Char的操作,包括assign(賦值)、eq(相等)、lt(小于)、compare(比較兩個字符串的大?。ength(獲取字符串的長度)、move(移動)、copy(拷貝)、assign(字符串賦值)、eof(結束符),它的代碼比較簡潔,這里不做說明。

type_compare

 

type_compare用于對兩種類型做運行時的匹配,判斷所給定的兩種類型是否相同。同樣通過特例化技術可以很輕松的實現它的代碼

迭代器

 

迭代器類是一種類似于smart pointer的東西,一般的它都會支持前置和后置的++和--操作,有一些特殊的迭代器同樣支持+=和-=操作。當然作為一種smart pointer少不了的是->和*操作,而對于比較操作,則比較的是迭代器所保存的值。

 

迭代器分為bidirectional_iterator和random_access_iterator兩種類型,前者只支持++和--操作而后者支持+和-運算符,之所以會定義出這兩種類型是為了提高算法的速度。對于一個迭代器來說同樣需要定義value_type、distance_type、pointer、reference、const_pointer、const_reference的類型。

 

反向迭代器

 

反向迭代器與正向的正好相反,應此我們可以類似的定義它的++為正向迭代器的--等運算符

iterator_traits

 

iterator_traits用于萃取出迭代器的所有特性,應此它比較簡單

 

template <typename Iterator>

struct iterator_traits

{

    typedef typename Iterator::value_type value_type;

    typedef typename Iterator::distance_type distance_type;

    typedef typename Iterator::pointer pointer;

    typedef typename Iterator::reference reference;

    typedef typename Iterator::const_pointer const_pointer;

    typedef typename Iterator::const_reference const_reference;

};

vector

 

vector是一種比較常用的容器,它的內部是一個連續的內存塊,應此它有兩個接口分別用于獲取內存塊已使用的大小和容器的大小,它們是size和capacity,同樣它也有一個reserve接口來調整它的容量。由于vector的內部是連續的,應此它只允許從后面插入元素,所以它有push_back、push_back_unique和pop_back方法。當然為了作為queue的容器,我還為其增加了pop_front方法用于刪除前端的元素。insert和erase用于在某個地方插入和刪除元素,add和add_unique用于插入另一個vector里的內容,而unique則會將容器內重復的元素刪除。

 

當然vector可以像數組一樣的使用,它支持方括號的運算符與at接口來獲取某個位置上的元素值。

 

vector容器就先介紹到這里,它的代碼你可以在QCore/Library/vector.h中找到。

list

 

list的內部則是一個雙向的鏈表,應此它在刪除前端的元素時會比vector快很多,它的接口基本跟vector相同,這里就不做過多的介紹了。由于vector是內存連續的,所以它可以直接通過索引來訪問某個元素,而list是一個雙向的鏈表,應此通過制定索引去訪問某個元素時會先看這個索引的值是否小于list長度的一半來決定是從list的頭部遍歷還是從list的尾部遍歷,它的代碼你可以在QCore/Library/list.h中找到。

queue和stack

 

queue是一種FIFO(先進先出)的結構,應此我們建議使用list作為它的容器,通過list的push_back和pop_front可以使代碼變的高效。它擁有front和back方法來獲取隊列中隊頭和隊尾的元素值,同樣在插入隊列時,你可以不加選擇的直接插入或是插入一個不重復的值。

 

stack是一種FILO(先進后出)的結構,同樣它擁有push、push_unique和pop方法以及top和bottom方法用于獲取棧頂端和底部的元素值。

 

對于這兩種結構的代碼,你可以在QCore/Library/queue.hQCore/Library/stack.h中找到。

rbtree

 

rbtree(紅黑樹)是一棵自平衡的二叉查找樹,應此它擁有較高的查找效率,紅黑樹有以下5條性質

 

性質1. 節點是紅色或黑色。

性質2. 根節點是黑色。

性質3 每個葉節點是黑色的。

性質4 每個紅色節點的兩個子節點都是黑色。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)

性質5. 從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點。

以上摘自百度百科

 

對于紅黑樹的每個節點,它都擁有它的key和value,當然我們是按照節點的key來排序的(廢話)。紅黑樹擁有insert_equal和insert_unique方法分別用于插入一個節點,前者允許待插入節點的key已存在于這棵樹中,而后者在插入時并不允許這個節點的key已存在于這棵樹中,應此它的返回值則是一個二元的。erase方法則提供了對于樹中某個節點的刪除操作,可以通過迭代器或某個key值來刪除其中的節點。

 

由于紅黑樹是一棵二叉查找樹,應此它應該具備find方法,用于在樹中查找某個節點,它返回的則是指向這個節點的一個迭代器。由于紅黑樹是有序的,應此可以通過maximum和minimum方法得到其中的最大和最小值。通過lower_bound和upper_bound可以得到屬于某個key的[first,last]區間,equal_range就是干這個活的,count方法可以得到某個key所對應的節點數。

 

rbtree就先介紹到這里,稍后我會在博客中繼續更新提供更完整的實現方法,它的代碼你可以在QCore/Library/rbtree.h中找到。

set和map

 

set是一種集合的結構,應此在集合中是不允許有重復的元素的,set是以rbtree作為容器的。應此它的insert方法對應于rbtree的insert_unique方法,同樣rbtree所具備的接口set也同樣擁有,set的key_type與value_type相同,都是給定的類型。

 

map則是一種key-value的directory結構,應此它的key是不允許重復的,map同樣是以rbtree作為容器的。應此它的insert方法同樣對應于rbtree的insert_unique方法,在map中除了rbtree的maximum、minimum、lower_bound、upper_bound、equal_range和count沒有之外其他接口基本全都擁有,map的key_type是給定的類型,而value_type則是一個以Key和T組成的二元組。

 

對于這兩種結構的代碼,你可以在QCore/Library/set.hQCore/Library/map.h中找到。

hashtable

 

hashtable是一種哈希結構,應此它的元素查找和插入是非??斓?。在這里我用的是吊桶法來處理元素插入時的沖突,當吊桶長度過長(默認是11個元素)時,會將桶的大小翻一倍然后重建整個hashtable以提高hashtable中元素的查找速度。

 

同樣的在hashtable中有insert_equal和insert_unique來分別插入允許相同和不同的元素,當遇到一個已有的元素時會將這個元素插入到第一個與它值相同的節點后面,這樣做的好處是可以簡單的實現equal_range方法。同時hashtable擁有value方法用于通過一個指定的key來查找到它對應的值,find方法則是用來查找一個key所對應的迭代器的。同樣的hashtable也擁有count方法來獲取某個key所對應的值的個數,maximum和minimum則是用來獲取最大值和最小值的。

 

hashtable的代碼,你可以在QCore/Library/hashtable.h中找到。

hashset和hashmap

 

hashset和hashmap基本與set和map相同,這里不過多做介紹,關于它們的代碼,你可以在QCore/Library/hashset.hQCore/Library/hashmap.h中找到。

basic_string

 

basic_string的實現方式基本和vector差不多,為了提高效率,在所有的插入操作中若新的長度的一倍小于一個定長(默認是512)字節時會申請新長度的一倍作為容器的容量。

 

與vector不同的是basic_string擁有c_str和data方法用于獲取字符指針,append方法往字符串尾部鏈接另一個字符串,assign方法給字符串賦值,find方法查找到第一個指定的字符串的位置,substr則用來獲取字符串中一部分的內容。

 

在basic_string中也有format的靜態方法來生成一個指定形式的字符串,其他用法基本與vecotr相同。它的代碼,你可以在QCore/Library/string.h中找到。

本章小結

 

上面介紹了所有的容器的接口和使用方法,以及在實現方式上的一些技巧。希望通過上面的介紹,讀者們能夠體會到STL為什么需要這么去設計、這么設計的好處是什么。

 

在我后來做regex的過程中,我深刻的體會到,選用一個合適的數據結構可以給代碼的運行效率帶來非常大的提升。比如給定NFA某個狀態,需要找出所有從這個狀態出發的邊,之前使用的是map結構來保存從某個狀態出發邊的vector,之后發現遍歷的速度非常緩慢,在換成hashmap之后,速度有顯著的提升。應此在實際編程過程中,選用一個合適的數據結構顯得尤為重要。

 

在使用線性結構時,一般在小數據量或不平凡插入或刪除數據的情況下,選用vector作為容器會更快一些。而在需要平凡插入或刪除數據的場合下,選用list作為容器會有更優異的結果。需要保持元素唯一性的情況下,我會優先選用set作為容器,而在數據量非常大的情況下,就會使用hashset來代替set。map則如它的名字那樣,適用于key-value的場合,而hashmap在數據量非常大的情況下使用。

算法

 

min和max函數分別用于求取最小值和最大值,fill_n用來填充若干個對象的值。copy_backward用來從后往前拷貝值。distance用來求給定區間[first, last)的長度。search用于在給定范圍[first1, last1)內查找符合序列[first2, last2)集合的值。swap和iterator_swap分別用于交換兩個值和兩個迭代器指向的值。sort用于將指定范圍[first, last)內的值排序,find用于在指定范圍[first, last)內查找指定的值。toArray用于將指定范圍[first, last)內的值轉換為內存連續的數組,compareArray則用于比較兩個數組內的值的個數和值是否相同。

 

具體的實現代碼,你可以在QCore/Library/algo.h中找到。

正則

 

通過重載+(相加)、-、|、+(前置)、*(前置)、!以及opt函數來生成正則表達式的ε-NFA,然后通過buildDFA函數生成DFA。通過parse和match可分析給定的字符串是否符合這個正則表達式,parse從頭開始跑DFA看這個字符串的開頭是否有符合這個正則表達式的字符串,而match則會找[first, last)區間內符合這個正則表達式的第一個字符串的相關結果。

 

具體的實現方法,你可以看http://www.shnenglu.com/lwch/archive/2013/02/15/197848.htmlhttp://www.shnenglu.com/lwch/archive/2013/02/23/198043.html兩篇文章,而代碼則可在QCore/Library/regex/regex.h中找到。

IO

 

IO模塊包含文件IO和標準輸入輸出IO,首先有兩個基類分別是basic_istream和basic_ostream分別作為輸入和輸出stream的基類,其中分別定義了運算符>>和<<,通過這兩個運算符可以直觀的看到是從stream輸出到變量或是從變量輸入到stream中。之后有stdstream_basic和fstream_basic都繼承自basic_istream和basic_ostream分別作為basic_stdstream和basic_fstream的基類,它們都有open、size、tell、seek、read、write和flush方法,它們都是對底層C函數的一些封裝。而在下一層的basic_stdstream和basic_fstream中則實現了運算符>>和<<的所有重載,這樣做的好處是可以使代碼更有條理性,并方便閱讀。

 

對于標準輸入輸出流來說,實際上是對stdin、stdout、stderr的一些封裝,當然里面也有一些比較特殊的接口,比如setColor(用于設置輸入輸出流的字體顏色)以及一些顏色相關的函數。

 

對于fstream來說它是針對所有文件的,應此它會多一個readAll接口用于一次性的讀出這個文件的所有內容,為了節省頻繁讀寫磁盤所造成的性能損耗,我們給它定義了兩個buffer用來做cache,當你要寫入文件時,它并不是馬上就直接往磁盤里寫的,而會加到buffer當中,當達到一個預值時才真正的寫入到磁盤。

那么IO模塊就先介紹到這里了,它們的代碼你可以在QCore/Library/ios.hQCore/Library/istream.h、QCore/Library/ostream.h、QCore/Library/fstream.h、QCore/Library/stdstream.h、QCore/Library/iostream.hQCore/Library/iostream.cpp中找到。

結束

 

上文介紹了大部分模塊的實現過程與實現過程中的心得,讓我們來按照順序回顧一下。

 

首先介紹了內存池的實現過程,以及在實現過程中遇到的一些問題,比如如何檢測內存泄漏、如何獲取調用堆棧等。

 

然后介紹了traits技術,它是用來萃取出一些特性用的,通過traits技術你可以得到一個類型是否為POD是否有默認構造函數等特性。而__container_traits則萃取出了容器的一些特性,比如值類型等等。通過char_traits我們得到了一些關于字符串的操作,比如求字符串的長度等。

 

之后又通過特例化,我們實現了一種比較兩個變量類型是否相同的手段。

 

接下來我們介紹了迭代器和反向迭代器,它們是一種類似于smart pointer的東西,我們可以通過一個[first, last]前閉后開區間來表示一個容器內的所有元素。然后我們通過iterator_traits萃取出了迭代器的一些特性,比如值類型等。

 

最后我們介紹了所有比較常用的容器,以及在某些場合下應該使用哪種容器來達到高效的目的。比如在數據量較大時使用hashset要比使用set在插入和查找速度要更快一些,而且時間負責度更穩定一些。

 

之后我們又介紹了一些常用算法,通過這些算法足以解決一些簡單的問題。比如排序和求取一個范圍[first, last]的長度等。

 

在正則這一章中,介紹了我們是如何通過一些運算符的重載來構造出某個正則表達式的狀態機的,以及如何通過運行這些狀態機來分析給定的字符串。

 

最后介紹了IO模塊,其中分為標準輸入輸出流和文件流,通過重載<<和>>運算符,可以直觀的看到是從流中講內容輸入到一個變量或是從一個變量中講內容輸入到流中。

 

希望通過本文可使讀者體會到作者在設計這個庫的時候所考慮的問題,以及對這個庫有一個大概的認識,稍后我會在我的博客中補齊所有沒有介紹過的模塊是如何實現的。

修改記錄

 

2013.4.23第一次編寫

2013.4.24添加容器的說明

2013.4.25添加hashtable、hashset、hashmap和basic_string結構的說明

2013.4.28添加算法和正則的說明

2013.4.30添加IO的說明,完結此文

posted on 2013-04-30 20:24 lwch 閱讀(2155) 評論(1)  編輯 收藏 引用 所屬分類: STL

評論:
# re: QCore/Library說明文檔 2013-05-03 15:56 | tb
比較有用的文檔  回復  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国内精品免费午夜毛片| 亚洲欧美欧美一区二区三区| 老司机精品视频一区二区三区| 国产日韩综合| 久久在线免费视频| 久久精品日产第一区二区三区| 国产一区二区三区四区老人| 久久久久久穴| 麻豆精品精品国产自在97香蕉| 最新日韩在线| 一区二区三区波多野结衣在线观看| 国产精品久久久久一区| 亚洲欧美视频| 久久综合色8888| 99精品久久| 亚洲一区二区三区精品动漫| 国产亚洲精久久久久久| 免费亚洲网站| 国产精品国产三级国产aⅴ浪潮| 午夜精品偷拍| 久色成人在线| 香蕉久久一区二区不卡无毒影院| 久久精品av麻豆的观看方式| 亚洲精品欧洲精品| 午夜一区在线| 99re66热这里只有精品3直播| 亚洲欧美精品| 亚洲看片一区| 久久激情网站| 亚洲欧美激情四射在线日 | 亚洲精品在线电影| 国产亚洲精久久久久久| 亚洲乱码国产乱码精品精可以看| 国产欧美日韩91| 亚洲国产一区二区在线| 欧美日本韩国| 欧美a一区二区| 国产欧美日韩一区二区三区在线观看 | 午夜影院日韩| 欧美电影免费观看高清| 久久久高清一区二区三区| 欧美激情第4页| 久久aⅴ国产欧美74aaa| 欧美久久一区| 欧美成人精品三级在线观看| 国产精品中文在线| 日韩一级精品视频在线观看| 在线观看一区二区视频| 性欧美18~19sex高清播放| 亚洲午夜在线观看| 欧美极品一区| 亚洲丰满在线| 亚洲丶国产丶欧美一区二区三区| 午夜精品久久久久久99热软件| 亚洲天堂视频在线观看| 99在线精品观看| 99在线精品观看| 亚洲精品在线观看免费| 久久先锋资源| 欧美成人黄色小视频| 国产一区二区精品在线观看| 亚洲综合国产| 欧美一级大片在线观看| 国产精品美女久久| 一区二区三区日韩精品| 亚洲午夜视频在线观看| 欧美日韩一区在线播放| 亚洲精品资源美女情侣酒店| 亚洲精品一区在线观看香蕉| 欧美 日韩 国产一区二区在线视频 | 欧美伊人久久大香线蕉综合69| 欧美午夜不卡视频| 日韩一级免费观看| 亚洲制服av| 国产日韩1区| 欧美中文在线字幕| 欧美va亚洲va国产综合| 亚洲激情成人在线| 欧美日韩国产区| 亚洲视频在线观看免费| 久久精品国产亚洲高清剧情介绍| 欧美美女bb生活片| 亚洲精品一区久久久久久| 一区二区不卡在线视频 午夜欧美不卡在 | 亚洲在线视频一区| 国产精品日本一区二区| 久久gogo国模裸体人体| 欧美成人免费观看| 亚洲午夜精品17c| 国产日韩欧美亚洲| 男人插女人欧美| 一区二区三区高清不卡| 久久久www成人免费毛片麻豆| 1024国产精品| 国产精品国产三级国产aⅴ9色| 午夜精品久久久久久久白皮肤| 麻豆精品传媒视频| 一区二区欧美视频| 国内精品一区二区| 欧美日韩一区二区三区视频 | 亚洲欧洲一区二区在线播放| 日韩视频免费在线观看| 国产欧美日韩亚洲精品| 免费久久99精品国产| 一区二区三区久久久| 美日韩免费视频| 亚洲一区二区3| 在线欧美日韩精品| 国产精品性做久久久久久| 老司机午夜精品视频在线观看| 亚洲视频一区二区| 亚洲国产精品va| 久久久成人精品| 亚洲欧美一区二区在线观看| 影音先锋久久| 国产伦精品一区二区三区照片91| 免费人成精品欧美精品| 亚洲午夜极品| 欧美日韩成人一区二区| 久久久蜜桃精品| 亚洲在线观看| 亚洲卡通欧美制服中文| 米奇777在线欧美播放| 欧美一区二区在线看| 一区二区三区精品| 亚洲激情成人| 亚洲第一天堂av| 国产揄拍国内精品对白| 国产精品一区二区三区久久久| 欧美乱妇高清无乱码| 男女av一区三区二区色多| 久久噜噜噜精品国产亚洲综合| 亚洲欧美另类综合偷拍| 亚洲性人人天天夜夜摸| 正在播放欧美一区| 99视频一区| 亚洲麻豆av| 99国产麻豆精品| 亚洲日本中文字幕区| 嫩草影视亚洲| 欧美ab在线视频| 欧美电影免费网站| 欧美激情亚洲另类| 欧美风情在线观看| 欧美激情中文字幕乱码免费| 女人色偷偷aa久久天堂| 女生裸体视频一区二区三区 | 亚洲缚视频在线观看| 狠狠色狠狠色综合人人| 激情亚洲一区二区三区四区| 国产日韩一区欧美| 国产自产女人91一区在线观看| 国产在线视频欧美一区二区三区| 国产一区二区三区av电影| 黄色一区二区三区四区| 影院欧美亚洲| 亚洲日韩欧美视频一区| 一区二区免费在线观看| 亚洲一级一区| 久久激情综合| 欧美11—12娇小xxxx| 亚洲精品1234| 亚洲一区二区三区四区五区黄 | 91久久精品国产91久久性色tv | 久热精品视频| 亚洲国产精品免费| 日韩午夜精品| 欧美一区二区三区播放老司机| 久久蜜桃av一区精品变态类天堂| 猛干欧美女孩| 国产精品高潮呻吟久久| 国产在线精品自拍| 亚洲精品国产精品国自产观看 | 尤物精品在线| 亚洲影院色在线观看免费| 久久精品欧洲| 亚洲精品久久久久久久久| 亚洲一区免费网站| 久久亚洲精品视频| 国产精品网红福利| 亚洲国产精品一区制服丝袜| 亚洲午夜女主播在线直播| 久久久91精品国产一区二区精品| 欧美激情视频在线播放| 亚洲一级网站| 欧美国产日韩a欧美在线观看| 国产精品视频你懂的| 亚洲欧洲久久| 久久久7777| 一区二区免费在线播放| 久久一二三国产| 国产乱人伦精品一区二区| 亚洲精品亚洲人成人网| 久久伊人亚洲| 欧美国产精品专区| 国产精品日韩一区二区三区| 亚洲国产日韩一区| 久久国产视频网站| 亚洲系列中文字幕| 欧美激情视频在线播放 |