This article initially implements the list linked list through the PHP FFI feature
union list
{
int val;
char *valStr;
};
struct ArrayStringList
{
int length; //当前长度
int capacity; //容量
char *data; //数组指针
};
<?php
// php 字符串转C char指针
function stringToCharPtr(string $str)
{
$strChar = str_split($str);
$c = FFI::new('char[' . count($strChar) . ']', false);
foreach ($strChar as $i => $char) {
$c[$i] = $char;
}
return FFI::cast(FFI::type('char *'), $c);
}
class FFIHelper
{
private static $ffi;
public static function create()
{
if (empty(self::$ffi)) {
self::$ffi = \FFI::load("./test.h");
}
return self::$ffi;
}
}
class StringArray
{
private $char;
private $ArrayList;
public function __construct(int $capacity = 0)
{
if ($capacity > 0) {
$this->create($capacity);
}
}
/**
* 创建list
*/
public function create(int $capacity)
{
if (!is_numeric($capacity) || $capacity <= 0) {
throw new \Exception("list长度不可以为0");
}
$this->char = \FFI::new ('char*[' . ($capacity) . ']', false, true);
$this->ArrayList = FFIHelper::create()->new('struct ArrayStringList');
$this->ArrayList->capacity = $capacity;
}
public function append($string)
{
$postion = $this->ArrayList->length;
if ($postion >= $this->ArrayList->capacity) {
$this->grow($this->ArrayList->capacity * 2);
}
$this->char[$postion] = stringToCharPtr($string . "\0");
if ($postion == 0) {
$this->ArrayList->data = $this->char[0];
}
$this->ArrayList->length++;
}
public function get($postion)
{
return $this->ArrayList->data;
}
public function delete($postion)
{
if ($postion < 0) {
throw new \Exception("删除位置不可以小于0");
}
if ($postion > $this->ArrayList->length) {
throw new \Exception("删除位置大于list长度");
}
$node = $this->ArrayList->data + $postion;
for ($i = $postion + 1; $i < $this->ArrayList->length; $i++) {
}
}
public function length()
{
return $this->ArrayList->length;
}
/**
* 增加数组长度
*/
public function grow($size)
{
if ($size < $this->ArrayList->capacity) {
throw new \Exception("无需增加list容量");
}
$oldData = $this->ArrayList->data;
$newData = \FFI::new ('char*[' . ($size) . ']', false, true);
\FFI::memcpy($newData, $this->char, \FFI::sizeof($oldData) * $this->ArrayList->length);
$this->ArrayList->data = $newData[0];
$this->char = $newData;
$this->ArrayList->capacity = $size;
\FFI::free($oldData);
}
public function getList()
{
return $this->ArrayList;
}
public function __destruct()
{
}
}
$star_memory = memory_get_usage();
$start = microtime(true);
$list = new StringArray(1000000);
var_dump($list->append("aaas你好"));
var_dump($list->append("aaas你好"));
var_dump($list->append("aaas你好"));
$i = 0;
$data = [];
while (true) {
$list->append("aaas你好");
//$data[] = "aaas你好" . $i;
$i++;
if ($i > 1000000) {
break;
}
}
var_dump(FFI::string($list->get(0)));
$end_memory = memory_get_usage();
$elapsed = microtime(true) - $start;
echo "That took $elapsed seconds.\n";
var_dump((($end_memory - $star_memory) / 1024 / 1024) . "M");
Due to the processing of the underlying strings in PHP, the same string will only be stored once, and the number of references is represented by a counter, but the strings implemented in this article are not considered to be processed. Thus, a new string is recreated each time.
Through the code test in the text, it is found that even if the string is processed, the memory usage will be optimized by at least 3 times. Of course, the fly in the ointment is that it takes a long time to convert the string to a char pointer, and it needs to be optimized.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。