欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

slice 实现原理

程序员文章站 2022-05-29 08:05:59
package main /* #include */ import "C" import ( "unsafe" "fmt" ) type Slice struct { Data unsafe.Pointer //万能指针类型 对应C语言中的void* len int //有效... ......
package main

/*
#include <stdlib.h>
 */
import "c"
import (
	"unsafe"
	"fmt"
)

type slice struct {
	data unsafe.pointer //万能指针类型 对应c语言中的void*
	len  int            //有效的长度
	cap  int            //有效的容量
}

const tag = 8

/*
func main() {
	//定义一个切片
	//1、数据内存地址 2、len 有效数据长度 3、cap 可扩容的有效容量  24字节
	var s []int

	//unsafe.sizeof 计算数据类型在内存中占的字节大小
	fmt.println(unsafe.sizeof(s))
}
*/
/*
func main(){
	var i interface{}
	i=10//只支持== !=

	//类型断言  是基于接口类型数据的转换
	//value,ok:=i.(int)
	//if ok{
	//	fmt.println("整型数据:",value)
	//	fmt.printf("%t\n",value)
	//}
	//反射获取接口的数据类型
	//t:=reflect.typeof(i)
	//fmt.println(t)

	//反射获取接口类型数据的值
	v:=reflect.valueof(i)
	fmt.println(v)

	i1:=10
	i2:=20

	if reflect.typeof(i1)==reflect.typeof(i2){
		v1:=reflect.valueof(i1)
		v2:=reflect.valueof(i2)
		结果=v1+v2
	}
}
*/
//create(长度 容量 数据)
func (s *slice) create(l int, c int, data ...int) {
	//如果数据为空返回
	if len(data) == 0 {
		return
	}
	//长度小于0 容量小于0 长度大于容量 数据大于长度
	if l < 0 || c < 0 || l > c || len(data) > l {
		return
	}
	//ulonglong unsigned long long  无符号的长长整型
	//通过c语言代码开辟空间 存储数据
	//如果堆空间开辟失败 返回值为null 相当于nil 内存地址编号为0的空间
	s.data = c.malloc(c.ulonglong(c) * 8)
	s.len = l
	s.cap = c

	//转成可以计算的指针类型
	p := uintptr(s.data)
	for _, v := range data {
		//数据存储
		*(*int)(unsafe.pointer(p)) = v
		//指针偏移
		p += tag
		//p+=unsafe.sizeof(1)
	}
}

//print 打印切片
func (s *slice) print() {
	if s == nil {
		return
	}

	//将万能指针转成可以计算的指针
	p := uintptr(s.data)
	for i := 0; i < s.len; i++ {
		//获取内存中的数据
		fmt.print(*(*int)(unsafe.pointer(p)), " ")
		p += tag
	}

}

//切片追加
func (s *slice) append(data ...int) {
	if s == nil {
		return
	}
	if len(data) == 0 {
		return
	}

	//如果添加的数据超出了容量
	if s.len+len(data) > s.cap {
		//扩充容量
		//c.realloc(指针,字节大小), go 语言 2 倍扩容。
		s.data = c.realloc(s.data, c.ulonglong(s.cap)*2*8)
		//改变容量的值
		s.cap = s.cap * 2
	}

	p := uintptr(s.data)
	for i := 0; i < s.len; i++ {
		//指针偏移
		p += tag
	}

	//添加数据
	for _, v := range data {
		*(*int)(unsafe.pointer(p)) = v
		p += tag
	}
	//更新有效数据(长度)
	s.len = s.len + len(data)
}

//获取元素 getdata(下标)  返回值为int 元素
func (s *slice) getddata(index int) int {
	if s == nil || s.data == nil {
		return 0
	}
	if index < 0 || index > s.len-1 {
		return 0
	}

	p := uintptr(s.data)
	for i := 0; i < index; i++ {
		p += tag
	}
	return *(*int)(unsafe.pointer(p))
}

//查找元素 search(元素)返回值为int 下标
func (s *slice) search(data int) int {
	if s == nil || s.data == nil {
		return -1
	}

	p := uintptr(s.data)
	for i := 0; i < s.len; i++ {
		//查找数据  返回第一次元素出现的位置
		if *(*int)(unsafe.pointer(p)) == data {
			return i
		}
		//指针偏移
		p += tag
	}
	return -1
}

//删除元素 delete(下标)
func (s *slice) delete(index int) {
	if s == nil || s.data == nil {
		return
	}
	if index < 0 || index > s.len-1 {
		return
	}

	//将指针指向需要删除的下标位置
	p := uintptr(s.data)
	for i := 0; i < index; i++ {
		p += tag
	}

	//用下一个指针对应的值为当前指针对应的值进行赋值
	temp := p
	for i := index; i < s.len; i++ {
		temp += tag
		*(*int)(unsafe.pointer(p)) = *(*int)(unsafe.pointer(temp))
		p += tag
	}

	s.len--
}

//插入元素 insert(下标 元素)
func (s *slice) insert(index int, data int) {
	if s == nil || s.data == nil {
		return
	}
	if index < 0 || index > s.len-1 {
		return
	}

	//如果插入数据是最后一个
	//if index == s.len-1 {
	//	p := uintptr(s.data)
	//
	//	//for i := 0; i < s.len; i++ {
	//	//	p += tag
	//	//}
	//	p += tag * uintptr(s.len-1)
	//	*(*int)(unsafe.pointer(p)) = data
	//	s.len++
	//	return
	//}
	//调用追加方法
	if index == s.len-1 {
		s.append(data)
		return
	}

	//获取插入数据的位置
	p := uintptr(s.data)
	for i := 0; i < index; i++ {
		p += tag
	}
	//获取末尾的指针位置

	temp := uintptr(s.data)
	temp += tag * uintptr(s.len)

	//将后面数据依次向后移动
	for i := s.len; i > index; i-- {
		//用前一个数据为当前数据赋值
		*(*int)(unsafe.pointer(temp)) = *(*int)(unsafe.pointer(temp - tag))
		temp -= tag
	}

	//修改插入下标的数据
	*(*int)(unsafe.pointer(p)) = data
	s.len++
}

//销毁切片
func (s *slice) destroy() {
	//调用c语言  适释放堆空间
	c.free(s.data)
	s.data = nil
	s.len = 0
	s.cap = 0
	s = nil
}