婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 使用C++來編寫Ruby程序擴展的教程

使用C++來編寫Ruby程序擴展的教程

熱門標簽:柯城手機地圖如何做地圖標注 AI電銷機器人 線路 外呼線路從哪里出來的 漯河電銷 天津外呼系統怎么收費 巫師3地圖標注魔力之所 淮安自動外呼系統供應商 中牟外呼系統違法嗎 征服者企業地圖標注

Ruby 最酷的功能之一就是使用 C/C++ 定義的應用程序編程接口 (API) 擴展它。Ruby 提供了 C 頭文件 ruby.h,它隨附提供了許多功能,可使用這些功能創建 Ruby 類、模塊和更多內容。除了頭文件,Ruby 還提供了其他幾個高層抽象來擴展基于本地 ruby.h 構建的 Ruby,本文要介紹的是 Ruby Interface for C++ Extensions 或 Rice。
創建 Ruby 擴展

在進行任何 Ruby 的 C API 或 Rice 擴展前,我想明確地介紹一下創建擴展的標準過程:

  •     您具有一個或多個 C/C++ 源代碼,可使用它們構建共享庫。
  •     如果您使用 Rice 創建擴展,則需要將代碼鏈接到 libruby.a 和 librice.a。
  •     將共享庫復制到同一文件夾,并將該文件夾作為 RUBYLIB 環境變量的一部分。
  •     在 Interactive Ruby (irb) prompt/ruby 腳本中使用常見的基于 require 的加載。如果共享庫名為 rubytest.so,只需鍵入 require 'rubytest' 即可加載共享庫。

假設頭文件 ruby.h 位于 /usr/lib/ruby/1.8/include 中,Rice 頭文件位于 /usr/local/include/rice/include 中,并且擴展代碼位于文件 rubytest.cpp 中。 清單 1 顯示了如何編譯和加載代碼。
清單 1. 編譯和加載 Ruby 擴展

bash# g++ -c rubytest.cpp –g –Wall -I/usr/lib/ruby/1.8/include \

  -I/usr/local/include/rice/include
bash# g++ -shared –o rubytest.so rubytest.o -L/usr/lib/ruby/1.8/lib \

  -L/usr/local/lib/rice/lib -lruby –lrice –ldl -lpthread
bash# cp rubytest.so /opt/test
bash# export RUBYLIB=$RUBYLIB:/opt/test
bash# irb
irb> require 'rubytest'
=> true

Hello World 程序

現在,您已經準備好使用 Rice 創建自己的首個 Hello World 程序。您使用名為 Test 的 Rice API 和名為 hello 的方法創建了一個類,用它來顯示字符串 "Hello, World!"。當 Ruby 解釋器加載擴展時,會調用函數 Init_shared library name>。對于 清單 1 的 rubytest 擴展,此調用意味著 rubytest.cpp 已定義了函數 Init_rubytest。Rice 支持您使用 API define_class 創建自己的類。清單 2 顯示了相關代碼。
清單 2. 使用 Rice API 創建類

#include "rice/Class.hpp"
extern "C"
void Init_rubytest( ) { 
 Class tmp_ = define_class("Test");
}

當您在 irb 中編譯和加載清單 2 的代碼時,應得到 清單 3 所示的輸出。
清單 3. 測試使用 Rice 創建的類

irb> require ‘rubytest'
=> true
irb> a = Test.new
=> #Test:0x1084a3928>
irb> a.methods
=> ["inspect", "tap", "clone", "public_methods", "__send__", 
   "instance_variable_defined?", "equal?", "freeze", …]

注意,有幾個預定義的類方法可供使用,比如 inspect。出現這種情況是因為,定義的 Test 類隱式地衍生自 Object 類(每個 Ruby 類都衍生自 Object;實際上,Ruby 中的所有內容(包括數字)都是基類為 Object 的對象)。

現在,為 Test 類添加一個方法。清單 4 顯示了相關代碼。
清單 4. 為 Test 類添加方法

void hello() {
  std::cout  "Hello World!";
}
extern "C"
 void Init_rubytest() {
   Class test_ = define_class("Test")
     .define_method("hello", hello);
}

清單 4 使用 define_method API 為 Test 類添加方法。注意,define_class 是返回一個類型為 Class 的對象的函數;define_method 是 Module_Impl 類的成員函數,該類是 Class 的基類。下面是 Ruby 測試,驗證所有內容是否都運行良好:

irb> require ‘rubytest'
=> true
irb> Test.new.hello
Hello, World!
=> nil

將參數從 Ruby 傳遞到 C/C++ 代碼

現在,Hello World 程序已正常運行,嘗試將參數從 Ruby 傳遞到 hello 函數,并讓函數顯示與標準輸出 (sdtout) 相同的輸出。最簡單的方法是為 hello 函數添加一個字符串參數:

void hello(std::string args) {
  std::cout  args  std::endl;
}
extern "C"
 void Init_rubytest() {
   Class test_ = define_class("Test")
     .define_method("hello", hello);
}

在 Ruby 環境中,以下是調用 hello 函數的方式:

irb> a = Test.new
Test:0x0145e42112>
irb> a.hello "Hello World in Ruby"
Hello World in Ruby
=> nil

使用 Rice 最出色的一點是,無需進行任何特殊操作將 Ruby 字符串轉換為 std::string。

現在,嘗試在 hello 函數中使用字符串數組,然后檢查如何將信息從 Ruby 傳遞到 C++ 代碼。最簡單的方式是使用 Rice 提供的 Array 數據類型。在頭文件 rice/Array.hpp 中定義 Rice::Array,使用 Rice::Array 的方式類似于使用 Standard Template Library (STL) 容器。還要將常見的 STL 樣式迭代器等內容定義為 Array 接口的一部分。清單 5 顯示了 count 例程,該例程使用 Rice Array 作為參數。
清單 5. 顯示 Ruby 數組

#include "rice/Array.hpp"

void Array_Print (Array a)  {
   Array::iterator aI = a.begin();
   Array::iterator aE = a.end();
   while (aI != aE) {
    std::cout  "Array has "  *aI  std::endl;
    ++aI;
   }
 }

現在,下面是此解決方案的魅力所在:假設您擁有 std::vectorstd::string> 作為 Array_Print 參數。下面是 Ruby 拋出的錯誤:

>> t = Test.new
=> #Test:0x100494688>
>> t.Array_Print ["g", "ggh1", "hh1"]
ArgumentError: Unable to convert Array to std::vectorstd::string, 
  std::allocatorstd::string> >
 from (irb):3:in `hello'
 from (irb):3

但是,使用此處顯示的 Array_Print 例程,Rice 負責執行從 Ruby 數組到 C++ Array 類型的轉換。下面是樣例輸出:

>> t = Test.new
=> #Test:0x100494688>
>> t.Array_Print ["hello", "world", "ruby"]
Array has hello
Array has world
Array has ruby
=> nil

現在,嘗試相反的過程,將 C++ 的數組傳遞到 Ruby 環境。請注意,在 Ruby 中,數組元素不一定是同一類型的。清單 6 顯示了相關代碼。
清單 6. 將數組從 C++ 傳遞到 Ruby

#include "rice/String.hpp"
#include "rice/Array.hpp"
using namespace rice; 

Array return_array (Array a) {
   Array tmp_;
   tmp_.push(1);
   tmp_.push(2.3);
   tmp_.push(String("hello"));
   return tmp_;
 }

清單 6 明確顯示了您可以在 C++ 中創建具有不同類型的 Ruby 數組。下面是 Ruby 中的測試代碼:

>> x = t.return_array
=> [1, 2.3, "hello"]
>> x[0].class
=> Fixnum
>> x[1].class
=> Float
>> x[2].class
=> String

如果我沒有更改 C++ 參數列表的靈活性,會怎么樣?

更常見的情況是具有這樣的靈活性,您將發現 Ruby 接口旨在將數據轉換為 C++ 函數,該函數的簽名無法更改。例如,考慮需要將字符串數組從 Ruby 傳遞到 C++ 的情形。C++ 函數簽名如下所示:

void print_array(std::vectorstd::string> args)

實際上,您在這里尋找的是某種 from_ruby 函數,Ruby 數組使用該函數并將它轉換為 std::vectorstd::string>。這正是 Rice 提供的內容,具有下列簽名的 from_ruby 函數:

template typename T>
T from_ruby(Object );

對于需要轉換為 C++ 類型的每種 Ruby 數據類型,需要針對模板詳細說明 from_ruby 例程。例如,如果將 Ruby 數組傳遞到上述處理函數,清單 7 顯示了應如何定義 from_ruby 函數。
清單 7. 將 ruby 數組轉換為 std::vectorstd::string>

template>
std::vectorstd::string> from_ruby std::vectorstd::string> > (Object o)  {
  Array a(o);
  std::vectorstd::string> v;
  for(Array::iterator aI = a.begin(); aI != a.end(); ++aI)
    v.push_back(((String)*aI).str());
  return v;
  }

請注意,不需要顯式地調用 from_ruby 函數。當從 Ruby 環境傳遞作為函數參數的 string 數組時,from_ruby 將它轉換為 std::vectorstd::string>。清單 7 中的代碼并不完美,但是您已經看到,Ruby 中的數組具有不同類型。相反,您調用了 ((String)*aI).str(),以便從 Rice::String 獲得 std::string。(str 是 Rice::String 的一種方法:查看 String.hpp 以了解有關的更多信息。)如果您處理的是最常見的情形,清單 8 顯示了相關的代碼。
清單 8. 將 ruby 數組轉換為 std::vectorstd::string>(通用情況)

template>
std::vectorstd::string> from_ruby std::vectorstd::string> > (Object o)  {
  Array a(o);
  std::vectorstd::string> v;
  for(Array::iterator aI = a.begin(); aI != a.end(); ++aI)
    v.push_back(from_rubystd::string> (*aI));
  return v;
  }

由于 Ruby 數組的每個元素仍然是類型為 String 的 Ruby 對象,因此可以假設 Rice 已定義了 from_ruby 方法,將此類型轉換為 std::string,不需要進行其他操作。如果情況并非如此,則需要為此轉換提供 from_ruby 方法。下面是 Rice 資源中 to_from_ruby.ipp 的 from_ruby 方法:

template>
inline std::string from_rubystd::string>(Rice::Object x) {
 return Rice::String(x).str();
}

在 Ruby 環境中測試此代碼。首先傳遞所有字符串的數組,如 清單 9 所示。
清單 9. 驗證 from_ruby 功能

>> t = Test.new
=> #Test:0x10e71c5c8>
>> t.print_array ["aa", "bb"]
aa bb
=> nil
>> t.print_array ["aa", "bb", 111]
TypeError: wrong argument type Fixnum (expected String)
 from (irb):4:in `print_array'
 from (irb):4

和預期一樣,首次調用 print_array 運行正常。由于沒有 from_ruby 方法來將 Fixnum 轉換為 std::string,因此第二次調用時,會導致 Ruby 解釋器拋出 TypeError。有幾種修復此錯誤的方法:例如,在 Ruby 調用期間,僅將字符串作為數組的一部分(比如 t.print_array["aa", "bb", 111.to_s])來傳遞,或者是在 C++ 代碼中,調用 Object.to_s。to_s 方法是 Rice::Object 接口的一部分,它會返回 Rice::String,它還有一個返回 std::string 的預定義 str 方法。清單 10 使用了 C++ 方法。
清單 10. 使用 Object.to_s 填充字符串向量

template>
std::vectorstd::string> from_ruby std::vectorstd::string> > (Object o)  {
  Array a(o);
  std::vectorstd::string> v;
  for(Array::iterator aI = a.begin(); aI != a.end(); ++aI)
    v.push_back(aI->to_s().str());
  return v;
  }

通常,清單 10 中的代碼更為重要,因為您需要處理用戶定義的類的自定義字符串表示。

使用 C++ 創建一個具有變量的完整類

您已經了解了在 C++ 代碼內如何創建 Ruby 類和相關函數。對于更通用的類,需要一種定義實例變量的方法,并提供一個 initialize 方法。要設置并獲得 Ruby 對象實例變量的值,可以使用 Rice::Object::iv_set 和 Rice::Object::iv_get 方法。清單 11 顯示了相關的代碼。
清單 11. 在 C++ 中定義 initialize 方法

void init(Object self) {
   self.iv_set("@intvar", 121);
   self.iv_set("@stringvar", String("testing"));
 }
Class cTest = define_class("Test").
             define_method("initialize", init);

使用 define_method API 將 C++ 函數聲明為 Ruby 類方法時,可選擇將 C++ 函數的第一個參數聲明為 Object,并且 Ruby 會使用調用實例的引用來填充此 Object。然后,在 Object 上調用 iv_set 來設置實例變量。下面是接口在 Ruby 環境中的外觀:

>> require 'rubytest'
=> true
>> t = Test.new
=> #Test:0x1010fe400 @stringvar="testing", @intvar=121>

同樣地,要返回實例變量,返回的函數需要接收在 Ruby 中引用對象的 Object,并對它調用 iv_get。清單 12 顯示了相關的代碼片段。
清單 12. 從 Ruby 對象檢索值

void init(Object self) {
   self.iv_set("@intvar", 121);
   self.iv_set("@stringvar", String("testing"));
 }
int getvalue(Object self) { 
  return self.iv_get("@intvar");
}
Class cTest = define_class("Test").
             define_method("initialize", init).
             define_method("getint", getvalue);

將 C++ 類轉換為 Ruby 類型

迄今為止,您已經將免費的函數(非類方法)包裝為 Ruby 類方法。您已經將引用傳遞給 Ruby 對象,方法是使用第一個參數 Object 聲明 C 函數。這種方法有用,但是在將 C++ 類包裝為 Ruby 對象時,這種方法不夠好用。要包裝 C++ 類,仍需要使用 define_class 方法,除非現在您使用 C++ 類類型對它進行了 “模板化” 。清單 13 中的代碼將 C++ 類包裝為 Ruby 類型。
清單 13. 將 C++ 類包裝為 Ruby 類型

class cppType {
  public:
   void print(String args) {
    std::cout  args.str()  endl;
   }
};
Class rb_cTest =
    define_classcppType>("Test")
     .define_method("print", cppType::print);

注意,如前所述,對 define_class 進行了模板化。盡管這種方法并不是適合所有此類。下面是您試圖實例化類型 Test 的對象時,Ruby 解釋器的記錄:

>> t = Test.new
TypeError: allocator undefined for Test
 from (irb):3:in `new'
 from (irb):3

剛剛發生了什么事?您需要將構造函數顯式地綁定到 Ruby 類型。(這是 Rice 的怪異之處之一。)Rice 為您提供了 define_constructor 方法來關聯 C++ 類型的構造函數。您還需要包含頭文件 Constructor.hpp。注意,即使在您的代碼中沒有顯式構造函數,您也必須這樣做。清單 14 提供了示例代碼。
清單 14. 將 C++ 構造函數與 Ruby 類型關聯起來

#include "rice/Constructor.hpp"
#include "rice/String.hpp"
class cppType {
  public:
  void print(String args) {
    std::cout  args.str()  endl;
   }
  };

Class rb_cTest =
    define_classcppType>("Test")
     .define_constructor(ConstructorcppType>())
    .define_method("print", cppType::print);

還可以將構造函數與使用 define_constructor 方法的參數列表關聯起來。Rice 進行此操作的方法是為模板列表添加參數類型。例如,如果 cppType 有一個接收整數的構造函數,那么您必須將 define_constructor 作為 define_constructor(ConstructorcppType, int>()) 進行調用。關于此處的一條警告:Ruby 類型沒有多個構造函數。因此,如果您有具有多個構造函數的 C++ 類型,并使用 define_constructor 將它們關聯起來,那么從 Ruby 環境的角度講,您可以像源代碼最后一個 define_constructor 定義的那樣,初始化具有(或沒有)參數的類型。清單 15 解釋了剛剛討論的所有內容。
清單 15. 將構造函數與參數關聯起來

class cppType {
  public:
   cppType(int m) {
    std::cout  m  std::endl;
   }
   cppType(Array a) {
    std::cout  a.size()  std::endl;
   }
   void print(String args) {
    std::cout  args.str()  endl;
   }
  };
Class rb_cTest =
    define_classcppType>("Test")
     .define_constructor(ConstructorcppType, int>())
     .define_constructor(ConstructorcppType, Array>())
     .define_method("print", cppType::print);

下面是來自 Ruby 環境的記錄。注意,最后關聯的構造函數是 Ruby 理解的構造函數:

>> t = Test.new 2
TypeError: wrong argument type Fixnum (expected Array)
 from (irb):2:in `initialize'
 from (irb):2:in `new'
 from (irb):2
>> t = Test.new [1, 2]
2
=> #Test:0x10d52cf48>

將新 Ruby 類型定義為模塊的一部分

從 C++ 定義新 Ruby 模塊可歸結為調用 define_module。要定義僅作為所述模塊一部分的類,請使用 define_class_under 而不是常用的 define_class 方法。define_class_under 的第一個參數是模塊對象。根據 清單 14,如果您打算將 cppType 定義為名為 types 的 Ruby 模塊的一部分,清單 16 顯示了如何進行此操作。
清單 16. 將類型聲明為模塊的一部分

#include "rice/Constructor.hpp"
#include "rice/String.hpp"
class cppType {
  public:
  void print(String args) {
    std::cout  args.str()  endl;
   }
  };

Module rb_cModule = define_module("Types");
Class rb_cTest =
    define_class_undercppType>(rb_cModule, "Test")
     .define_constructor(ConstructorcppType>())
    .define_method("print", cppType::print);

下面是在 Ruby 中使用相同聲明的方法:

>> include Types
=> Object
>> y = Types::Test.new [1, 1, 1]
3
=> #Types::Test:0x1058efbd8>

注意,在 Ruby 中,模塊名稱和類名稱必須以大寫字母開頭。如果您將模塊命名為 types 而不是 Types,Rice 不會出錯。

使用 C++ 代碼創建 Ruby 結構

您在 Ruby 中使用 struct 構造函數來快速創建樣本 Ruby 類。清單 17 顯示了使用名為 a、ab 和 aab 的三個變量創建類型 NewClass 的新類的方法。
清單 17. 使用 Ruby Struct 創建新類

>> NewClass = Struct.new(:a, :ab, :aab)
=> NewClass
>> NewClass.class
=> Class
>> a = NewClass.new
=> #struct NewClass a=nil, ab=nil, aab=nil>
>> a.a = 1
=> 1
>> a.ab = "test"
=> "test"
>> a.aab = 2.33
=> 2.33
>> a
=> #struct NewClass a=1, ab="test", aab=2.33>
>> a.a.class
=> Fixnum
>> a.ab.class
=> String
>> a.aab.class
=> Float

要在 C++ 中進行 清單 17 的等效編碼,您需要使用頭文件 rice/Struct.hpp 中聲明的 define_struct( ) API。此 API 返回 Rice::Struct。您將此 struct 創建的 Ruby 類與該類所屬的模塊關聯起來。這是 initialize 方法的目的。使用 define_member 函數調用定義各個類成員。注意,您已經創建了一個新的 Ruby 類型,可惜您沒有將任何 C++ 類型或函數與它關聯起來。下面是創建名為 NewClass 的類的方法:

#include "rice/Struct.hpp"
…
Module rb1 = define_module("Types");
define_struct().
    define_member("a").
    define_member("ab").
    define_member("aab").
    initialize(rb1, "NewClass");

結束語

本文介紹了一些背景知識:使用 C++ 代碼創建 Ruby 對象,將 C 樣式的函數作為 Ruby 對象方法進行關聯,在 Ruby 和 C++ 之間轉換數據類型,創建實例變量,以及將 C++ 類包裝為 Ruby 類型。您可以使用 ruby.h 頭文件和 libruby 實現所有這些操作,但是您需要編寫大量樣板代碼來結束所有操作。Rice 使這些工作變得更加簡單。在這里,祝您使用 C++ 針對 Ruby 環境編寫新擴展愉快! world!

您可能感興趣的文章:
  • Ruby on Rails下的圖像處理入門教程
  • 優化Ruby代碼使程序運行速度提高的例子
  • 詳解Ruby中范圍的概念

標簽:南昌 內江 甘孜 大慶 克拉瑪依 西雙版納 棗莊 河池

巨人網絡通訊聲明:本文標題《使用C++來編寫Ruby程序擴展的教程》,本文關鍵詞  使用,C++,來,編寫,Ruby,程序,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《使用C++來編寫Ruby程序擴展的教程》相關的同類信息!
  • 本頁收集關于使用C++來編寫Ruby程序擴展的教程的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    麻豆精品视频在线| 国产精品免费av| 日韩一区二区三区在线视频| 亚洲欧美在线观看| 成人污污视频在线观看| 久久一区二区三区四区| 亚洲综合免费观看高清在线观看| 精品亚洲porn| 7777精品伊人久久久大香线蕉经典版下载 | 亚洲午夜私人影院| 国产高清不卡二三区| 欧美精品在线一区二区三区| 国产精品网友自拍| 高清不卡一区二区| 亚洲欧美日韩在线| www.日韩大片| 五月天国产精品| 69成人精品免费视频| 粗大黑人巨茎大战欧美成人| 亚洲人成精品久久久久久| 91一区在线观看| 日本视频中文字幕一区二区三区| 久久精品人人做人人爽97| 色爱区综合激月婷婷| 狠狠色狠狠色综合| 国产精品久久久久久久久久久免费看 | 国产盗摄一区二区| 亚洲欧洲国产日本综合| 欧美日本一区二区在线观看| 麻豆精品视频在线观看免费| 亚洲欧美视频一区| 91精品国产综合久久精品图片| 亚洲成人中文在线| 欧美精品一区男女天堂| 成人av资源站| 午夜欧美2019年伦理 | 久久精品国产亚洲高清剧情介绍| 欧美一级片在线| 成人18精品视频| 亚洲一区二区精品视频| 色综合天天性综合| 香蕉加勒比综合久久| 欧美大胆一级视频| 91麻豆swag| 久久精品国产999大香线蕉| 国产精品热久久久久夜色精品三区 | 91国偷自产一区二区开放时间| 美国十次了思思久久精品导航| 亚洲色图一区二区| 国产亚洲欧美一区在线观看| 91精品国产全国免费观看| 成年人网站91| 国产美女主播视频一区| 日韩av不卡一区二区| 国产精品美女久久久久久久网站| 欧美日韩精品三区| 成人中文字幕电影| 日本午夜精品一区二区三区电影 | 亚洲少妇30p| 日韩视频一区二区三区| 欧美亚洲动漫精品| av电影在线观看完整版一区二区| 久久99久久99| 蜜乳av一区二区三区| 亚洲精品视频在线观看免费| 亚洲视频一区在线| 亚洲黄色小说网站| 一区二区三区四区不卡视频| 亚洲黄色免费网站| 亚洲va在线va天堂| 麻豆高清免费国产一区| 免费视频最近日韩| 极品少妇xxxx精品少妇| 国产一区二区h| 成人午夜视频在线| 99精品国产视频| 欧洲人成人精品| 91精品国产综合久久久久| 欧美成人官网二区| 国产亚洲精品免费| 国产欧美日韩不卡| 国产精品久久久久婷婷| 亚洲免费观看高清完整版在线观看| 亚洲免费成人av| 亚洲精品视频观看| 亚洲大片免费看| 亚洲一区二区三区三| 蜜桃一区二区三区在线观看| 韩国三级电影一区二区| 成人免费视频网站在线观看| av在线综合网| 欧美肥妇bbw| 久久精品亚洲乱码伦伦中文| 亚洲精品视频在线观看免费| 丝袜诱惑制服诱惑色一区在线观看| 午夜电影久久久| 国产露脸91国语对白| 在线观看www91| 国产亚洲精品资源在线26u| 一个色在线综合| 国产精品亚洲а∨天堂免在线| 成人午夜免费视频| 欧美一区二区三区思思人| 中文字幕乱码久久午夜不卡 | 国产精品久久久久一区二区三区共| 亚洲一区二区三区四区五区黄 | 精品一二线国产| 91丨porny丨蝌蚪视频| 欧美日韩成人综合天天影院| 2020国产精品| 一区二区三区国产豹纹内裤在线| 蜜臀av性久久久久蜜臀aⅴ| 韩国av一区二区三区在线观看| 国产成人精品www牛牛影视| 94色蜜桃网一区二区三区| 2023国产精华国产精品| 中文字幕第一区综合| 一区二区三区免费看视频| 国产黄色精品视频| 欧美猛男超大videosgay| 国产农村妇女毛片精品久久麻豆| 午夜精品成人在线| 91一区一区三区| 国产精品青草综合久久久久99| 日本午夜一区二区| 欧美日韩高清一区二区不卡| 亚洲四区在线观看| 成人av电影在线网| 国产亚洲精品精华液| 麻豆精品一区二区三区| 678五月天丁香亚洲综合网| 夜夜精品浪潮av一区二区三区| 成人免费av资源| 国产三级精品三级在线专区| 国产在线一区二区| 日韩片之四级片| 久久国产剧场电影| 51精品国自产在线| 亚洲小说欧美激情另类| 在线精品观看国产| 亚洲精选在线视频| 99天天综合性| 亚洲色图视频网| 国产a级毛片一区| 精品国产成人在线影院| 激情丁香综合五月| 日韩午夜激情电影| 美女精品一区二区| 精品国产免费一区二区三区四区| 麻豆国产91在线播放| 精品国产露脸精彩对白| 成人夜色视频网站在线观看| 国产精品视频看| 91成人国产精品| 日本三级亚洲精品| 精品国产麻豆免费人成网站| 国产精品综合视频| 亚洲视频 欧洲视频| 欧美剧情片在线观看| 国产在线国偷精品免费看| 国产日韩精品一区二区三区在线| 不卡的看片网站| 五月天一区二区三区| 精品国产不卡一区二区三区| av不卡免费电影| 天堂va蜜桃一区二区三区| 欧美va亚洲va| 99视频在线观看一区三区| 亚洲日本在线看| 69av一区二区三区| 成人一区二区三区| 亚洲国产成人高清精品| 日韩一区二区三区免费观看| 风间由美一区二区三区在线观看 | 国产福利不卡视频| 亚洲一区在线电影| 久久亚区不卡日本| 色婷婷精品久久二区二区蜜臀av | 久久er精品视频| 亚洲婷婷综合色高清在线| 欧美日韩一卡二卡| 国产毛片精品视频| 亚洲色图视频免费播放| 2021国产精品久久精品| 欧美色男人天堂| 成人黄色av电影| 国产在线精品不卡| 亚洲国产sm捆绑调教视频| 欧美精品一区视频| 91国偷自产一区二区三区成为亚洲经典 | 欧美三区免费完整视频在线观看| 国产精品主播直播| 亚洲成人黄色影院| 亚洲欧美日韩国产中文在线| 久久久国产午夜精品| 日韩一区二区电影| 在线观看视频一区二区| 色一情一乱一乱一91av| 国产精品一区二区视频| 免费在线一区观看|