精易论坛

标题: 比核心库快百倍系列 - 分割文本_快速 - 2 [打印本页]

作者: 福仔    时间: 2023-3-21 21:04
标题: 比核心库快百倍系列 - 分割文本_快速 - 2
本帖最后由 福仔 于 2023-3-21 22:00 编辑

上一个帖子, https://125.confly.eu.org/thread-14763101-1-1.html
上一个帖子有点问题, 比如分割("123", "456") 易语言会返回一个成员的数组, 这个是返回0个成员的数组, 属于bug
这次修复这个问题, 然后增加两个参数, 一个参数是和原来的分割文本一样, 返回指定的成员数, 另一个是预分配的成员数, 这个是用空间换时间
这次把c++的代码发出来, 有可以优化的地方还希望大佬们能优化一下, 或者提一个优化的方向
新增了一个4字节的数组类, 这个数组类只是测试用, 效率嘛肯定是比易语言数组要快, 只是很多方法都没写
等什么时候有闲时间把通用的内存类给写了之后就可以写增删成员的方法了

应该设计一个通用的内存类, 申请/释放/拷贝/重新分配内存 都在这个类里
然后其他类都继承或者内置这个内存类, 比如字符串或者数组
这样就不需要考虑分配内存的事了, 所有对象都只管往里写
有啥想法, 有能力实现的, 欢迎弄一个

[C++] 纯文本查看 复制代码
typedef LPVOID(WINAPI* PFN_Alloc)( DWORD );
typedef void(WINAPI* PFN_Free)( LPVOID );
struct PFN_CALL
{
    LPCSTR      str;            // 被分割的文本, 这个是外部传递进来的文本, 不能修改, 需要重新分配一块内存记录
    LPCSTR      subText;        // 用作分割的文本
    size_t      strLen;         // 被分割的文本的长度
    size_t      subTextLen;     // 用作分割的文本的长度
    PFN_Alloc   pfnAlloc;       // 分配内存的函数
    PFN_Free    pfnFree;        // 释放内存的函数
    LPINT*      pArr;           // 易语言的数组, 局部变量地址, *pArr是数组数据地址, 第一个成员是维数, 第二个成员是数组长度
    int         retCount;       // 要返回的成员数
    int         allocCount;     // 预分配的数组成员数, 首次分配的成员数就是这个数, 如果为0, 那就默认
};

// 不检测指针的有效性
__declspec( noinline ) int WINAPI split(PFN_CALL* call)
{
    LPSTR pStr;           // 被分割的文本, 这个是新分配的文本, 数组里的文本常用都是这个地址里的
    pStr = (LPSTR)call->pfnAlloc(call->strLen + 1);
    if ( pStr == 0 )
    {
        return 0;
    }
    if ( call->retCount < 1 )
    {
        call->retCount = 0x7fffffff;
    }
    else
    {
        // 走到这就是有限制的, 那就要预分配数组成员
        if ( call->allocCount < 1 || call->allocCount > call->retCount )
            call->allocCount = call->retCount;  // 预分配的成员数为0, 那就按返回的成员数来预分配
    }
    LPSTR pStart = pStr;
    LPCSTR pStart1 = call->str;
    while ( *pStart1 )
        *pStart++ = *pStart1++;
    *pStart = 0;
    pStart = pStr;
   
    size_t bufCount = 0;    // 预先分配这么多内存, 不够再分配
    LPINT pArr = 0;         // 最终返回的数组, 这个是易语言一维数组的格式
    size_t count = 0;       // 返回的数组成员数
    const size_t nStartData = 4;    // 起始存放数据的索引, 有两个成员是记录易语言数组的维数和成员数, 这里多分配数据保存其他
    const size_t firstIndex = nStartData - 2;
   
    LPCSTR pValue = pStr;
    LPCSTR pEnd = pStr + call->strLen;
    auto push_back = [&]()
    {
        if ( pValue == pEnd )
            return;
        if ( count + 1 > bufCount )
        {
            size_t newSize = bufCount * 2;
            if ( newSize == 0 )
            {
                // 走到这里就是首次分配内存, 需要根据用户传递的成员数来分配
                newSize = call->allocCount;     // 用户预定义的成员数, 如果为0则内部默认处理
                if ( newSize == 0 || newSize > 0x7fffffff )
                {
                    const size_t maxCount = 10000;  // 设定一个最大值, 要是首次计算的最大值超过这个值, 那就设置为这个值
                    newSize = call->strLen / call->subTextLen / 2;
                    if ( newSize > maxCount )
                        newSize = maxCount;
                    else if ( newSize < 10 )
                        newSize = call->strLen < 10 ? call->strLen : 10;
                }
            }

            // 分配易语言格式的数组内存, 数组成员数据是垃圾数据, 只写了数组维数
            size_t allocSize = newSize + nStartData + 1;
            LPINT arr = (LPINT)call->pfnAlloc(allocSize * sizeof(INT));

            if ( pArr )
            {
                allocSize = bufCount + nStartData + 1;
                for ( size_t i = nStartData; i < allocSize; i++ )
                    arr = pArr;   // 把旧的数组数据赋值到新的数组里
                call->pfnFree(pArr);
            }

            bufCount = newSize;
            pArr = arr;
        }
        size_t index = count + nStartData;
        pArr[index] = (INT)pValue;
        ++count;
    };
    while ( *pStr )
    {
        char& ch = *pStr++;
        if ( ch != call->subText[0] )
            continue;

        // 完全匹配, 需要匹配剩下的字符
        bool isContinue = false;
        for ( size_t i = 1; i < call->subTextLen; i++ )
        {
            if ( pStr[i - 1] != call->subText )
            {
                pStr += i - 1;
                isContinue = true;
                break;   // 只要有一个字符不相等, 那就不是完全匹配
            }
        }
        if ( isContinue )
            continue;

        // 走到这里就是完全匹配了, 处理下一段地址
        pStr--;
        for ( size_t i = 0; i < call->subTextLen; i++ )
            pStr = 0;    // 把分割的子文本修改成0

        push_back();
        if ( call->retCount == count )
            break;  // 成员数够了, 不继续分配了

        pStr += call->subTextLen;
        pValue = pStr;
    }
    if ( !pArr )
    {
        LPCSTR pStrStart = pEnd - call->strLen;
        // pEnd - 分割文本长度 = 被分割文本的起始地址
        // 如果上面的循环有走, 那pStr肯定是大于起始地址
        // 如果这里计算的起始地址和起始地址不相等, 那就是有分割, 0个匹配, 需要把整个文本作为一个成员
        // 如果想等, 那就是循环都没走, 传递的是空文本, 应该不会走到这
        if ( pStrStart == pStr )
            return 0;
    }

    if ( count < call->retCount )
        push_back();
    if ( !pArr )
    {
        call->pfnFree(pStart);
        return 0;
    }

    LPINT pOldArr = *call->pArr;
   
    pArr[firstIndex - 2] = (int)pOldArr;// 原来数组的地址
    pArr[firstIndex - 1] = (int)pArr;   // 分割记录的地址, 第0个成员的地址, 设置这个值是为了判断传递的数组是否是分割时记录的数组
   
    // 从这里开始就是易语言数组的格式了
    pArr[firstIndex + 0] = 1;           // 数组维数, 这个就是设置到易语言局部变量数组里的地址
    pArr[firstIndex + 1] = count;
    *call->pArr = &pArr[firstIndex];
    return count;   // 返回数组成员数
}

struct PFN_CALL_FREE
{
    PFN_Free    pfnFree;        // 释放内存的函数
    LPINT*      pArr;           // 易语言的数组, 局部变量地址, *pArr是数组数据地址, 第一个成员是维数, 第二个成员是数组长度
};

__declspec( noinline ) int WINAPI free_split(PFN_CALL_FREE* call)
{
    LPINT* pArr = call->pArr;
    LPINT arr = *pArr;
    if ( !arr )
        return 0;
    LPINT pTmp = arr - 2;
    if ( pTmp[1] != (int)pTmp )
        return 0;   // -1的位置不是记录的数组地址, 说明不是分割时记录的数组
   
    LPINT pOldArr = (LPINT)pTmp[0];
    *pArr = pOldArr;    // 把原来的数组地址赋值回去
   
    // 清理数组和文本数据
    LPSTR pStr = (LPSTR)arr[2];
    call->pfnFree(pStr);
    call->pfnFree(pTmp);
    return true;
}

__declspec( noinline ) int WINAPI free_split1(PFN_Free pfnFree, LPINT* pArr)
{
    LPINT arr = *pArr;
    if ( !arr )
        return 0;
    LPINT pTmp = arr - 2;
    if ( pTmp[1] != (int)pTmp )
        return 0;   // -1的位置不是记录的数组地址, 说明不是分割时记录的数组

    LPINT pOldArr = (LPINT)pTmp[0];
    *pArr = pOldArr;    // 把原来的数组地址赋值回去

    // 清理数组和文本数据
    LPSTR pStr = (LPSTR)arr[2];
    pfnFree(pStr);
    pfnFree(pTmp);
    return true;
}



下面这个是分割1的代码, 分割1需要改进, 目前分割1的效率比不上第一种分割
但是在c++里使用 vector的话, 会比第一种快.....
[C++] 纯文本查看 复制代码
typedef void( WINAPI* PFN_Insert )( LPCSTR, LPVOID pArg );
struct PFN_CALL1
{
    LPSTR       pStr;           // 被分割的文本, 这个是新分配的文本, 数组里的文本常用都是这个地址里的
    LPCSTR      subText;        // 用作分割的文本
    size_t      strLen;         // 被分割的文本的长度
    size_t      subTextLen;     // 用作分割的文本的长度
    PFN_Insert  pfnInsert;      // 把分割得到的地址传递出去, 让外部存放地址
    LPVOID      pArg;           // 传递给pfnInsert的参数
};
__declspec( noinline ) int WINAPI split1(PFN_CALL1* call)
{
    LPSTR pStr = call->pStr;
    LPSTR pStart = pStr;

    size_t bufCount = 0;    // 预先分配这么多内存, 不够再分配
    size_t count = 0;       // 返回的数组成员数
    const size_t nStartData = 4;    // 起始存放数据的索引, 有两个成员是记录易语言数组的维数和成员数, 这里多分配数据保存其他
    const size_t firstIndex = nStartData - 2;

    LPCSTR pValue = pStr;
    LPCSTR pEnd = pStr + call->strLen;

    while ( *pStr )
    {
        char& ch = *pStr++;
        if ( ch != call->subText[0] )
            continue;

        // 完全匹配, 需要匹配剩下的字符
        bool isContinue = false;
        for ( size_t i = 1; i < call->subTextLen; i++ )
        {
            if ( pStr[i - 1] != call->subText )
            {
                pStr += i - 1;
                isContinue = true;
                break;   // 只要有一个字符不相等, 那就不是完全匹配
            }
        }
        if ( isContinue )
            continue;

        // 走到这里就是完全匹配了, 处理下一段地址
        pStr--;
        for ( size_t i = 0; i < call->subTextLen; i++ )
            pStr = 0;    // 把分割的子文本修改成0

        ++count;
        call->pfnInsert(pValue, call->pArg);

        pStr += call->subTextLen;
        pValue = pStr;
    }
   

    LPCSTR pStrStart = pEnd - call->strLen;
    // pEnd - 分割文本长度 = 被分割文本的起始地址
    // 如果上面的循环有走, 那pStr肯定是大于起始地址
    // 如果这里计算的起始地址和起始地址不相等, 那就是有分割, 0个匹配, 需要把整个文本作为一个成员
    // 如果想等, 那就是循环都没走, 传递的是空文本, 应该不会走到这
    if ( pStrStart == pStr )
        return 0;
   
    if ( pValue != pEnd )
    {
        ++count;
        call->pfnInsert(pValue, call->pArg);
    }
   
    return count;   // 返回数组成员数
}






忘了上传源码....... 不要在意这些细节.....


作者: xtavoxing    时间: 2023-3-21 21:19
棒棒的..    \
作者: jgj    时间: 2023-3-21 21:39
厉害
作者: quary    时间: 2023-3-21 22:06
牛逼牛逼牛逼牛逼牛逼
作者: 瓶中仙子    时间: 2023-3-21 22:08

牛逼牛逼牛逼牛逼牛逼
作者: 亿万    时间: 2023-3-21 22:20

感谢分享
作者: 撒加    时间: 2023-3-21 22:27
        感谢分享,很给力!~
作者: 网络注册会员    时间: 2023-3-21 22:44
支持一下
作者: mgfz    时间: 2023-3-21 23:01
支持一个。
作者: 一尘不染    时间: 2023-3-21 23:46
感谢大佬开源
作者: Vze    时间: 2023-3-21 23:58
看看                 
作者: 易造轮    时间: 2023-3-21 23:58
让我看看
作者: pipicool    时间: 2023-3-22 00:43
学习一下
作者: vesslin    时间: 2023-3-22 02:43
牛逼牛逼牛逼牛逼牛逼
作者: 点点丶滴滴    时间: 2023-3-22 06:16
瞅瞅看
作者: cf2006a    时间: 2023-3-22 07:29
又更新了  下个修复下
作者: 飞鱼软件    时间: 2023-3-22 08:22
感谢分享 支持开源 !
作者: 396384183    时间: 2023-3-22 08:25
感谢分享
作者: 一指温柔    时间: 2023-3-22 08:31
感谢分享
作者: 794229345    时间: 2023-3-22 08:35
膜拜大佬!大佬牛B!
作者: wuqingg    时间: 2023-3-22 08:38
早上好,福仔老师!
作者: shinid8210    时间: 2023-3-22 08:38
牛逼  厉害
作者: 辽阳小哲    时间: 2023-3-22 08:49
感谢大佬提供源码。!
作者: 凌哥    时间: 2023-3-22 08:55
通用的内存类,有 你可以用mimalloc
作者: zifeiyu    时间: 2023-3-22 09:06
66666666666666666
作者: 小情缘    时间: 2023-3-22 09:12
牛逼  厉害
作者: jy2014    时间: 2023-3-22 09:28
学习下,谢谢分享
作者: wjswzj0    时间: 2023-3-22 09:47
学习下,谢谢分享
作者: msm1985    时间: 2023-3-22 09:55
看看
作者: 韦贝贝    时间: 2023-3-22 10:02
分割文本_快速
作者: gaoqing    时间: 2023-3-22 10:45
666支持一波
作者: chendipang    时间: 2023-3-22 11:26
666666666666666
作者: quary    时间: 2023-3-22 11:54
谢谢楼主分享!!! 好人一生平安!!!
作者: 吃兔    时间: 2023-3-22 13:28
6666666666666666666666
作者: 285275928    时间: 2023-3-22 13:43
如果您要查看本帖隐藏内容请回复
作者: hellohexiang    时间: 2023-3-22 14:23
谢谢分享
作者: 361322548    时间: 2023-3-22 15:26
忘了上传源码....... 不要在意这些细节.....
作者: wanpl2006    时间: 2023-3-22 15:27
楼主辛苦了,谢谢楼主,感谢楼主分享,楼主好人一生平安!!!
作者: kyo9766    时间: 2023-3-22 16:34
学习一下算法,感谢分享
作者: shituo    时间: 2023-3-22 17:24
忘了上传源码....
作者: Conquer    时间: 2023-3-22 17:50
所以什么时候加入精易模块全家桶一键调用~
作者: dlq663    时间: 2023-3-22 18:47

作者: int0826    时间: 2023-3-22 19:18
所以什么时候加入精易模块全家桶一键调用~
作者: NiceAys    时间: 2023-3-22 21:31
谢谢分享
作者: 沈远    时间: 2023-3-22 21:45
通用的内存类
作者: wyj159    时间: 2023-3-22 22:22
瞧瞧,xialai kankan
作者: 灵感吖    时间: 2023-3-22 22:46
支持一下,学习看看~~~
作者: 794229345    时间: 2023-3-22 22:58
学习一下算法,感谢分享
作者: 枕风宿雪多年    时间: 2023-3-22 23:06
学习一下
作者: 治愈勇者    时间: 2023-3-23 06:18
来看看
作者: By名扬    时间: 2023-3-23 06:41
楼主辛苦了,谢谢楼主,感谢楼主分享,楼主好人一生平安!!!
作者: kanhaiyouyue    时间: 2023-3-23 08:36
楼主辛苦了,期待第三版,加油
作者: 一指温柔    时间: 2023-3-23 09:32
谢谢分享
作者: renjianhong48we    时间: 2023-3-23 11:00
感谢分享
作者: 老二天天干活    时间: 2023-3-23 16:11
感谢分享,很给力!~
作者: z805373651    时间: 2023-3-23 18:08
感谢分享
作者: ccok    时间: 2023-3-23 18:45
#在这里快速回复#要在意这些细节....
作者: wool6    时间: 2023-3-23 19:23
忘了上传源码....... 不要在意这些细节..
作者: lml164    时间: 2023-3-23 19:29
忘了上传源码....... 不要在意这些细节.....
作者: Shanks    时间: 2023-3-23 21:24

作者: l7518597    时间: 2023-3-23 23:11
感谢分享
作者: snufgpl    时间: 2023-3-24 00:50
感谢分享,很给力!~
作者: woxl    时间: 2023-3-24 01:34
不要在意这些细节
作者: lvzhi_123    时间: 2023-3-24 07:47
感谢分享
作者: Seven3in    时间: 2023-3-24 10:21
学习学习
作者: 天使与恶魔    时间: 2023-3-24 10:28
66666666666666
作者: guyue98    时间: 2023-3-24 11:36
谢谢分享
作者: shentong    时间: 2023-3-24 13:24
kkkkkkkkkkkkk
作者: lm88818    时间: 2023-3-24 13:49
        感谢分享,很给力!
作者: lm88818    时间: 2023-3-24 15:01
学习学习
作者: 湿妇    时间: 2023-3-24 15:15
6666666666666666               
作者: 103029110    时间: 2023-3-24 23:32
6666666666666666         
作者: 易股道    时间: 2023-3-25 09:55
快百倍系列
作者: zu616    时间: 2023-3-25 10:13
个测试用的数组, 加入180万个成员耗时不到一秒
作者: fu1uzv    时间: 2023-3-25 14:39
        感谢分享,很给力!~
作者: 创拓    时间: 2023-3-25 16:38
66666666666666666
作者: FUYUEPC    时间: 2023-3-25 21:05
非常不错,看了就要回复,留名!@!!!!
作者: 1946222945    时间: 2023-3-25 21:50
看看怎么样
作者: pkwwfpkwwf    时间: 2023-3-25 23:45
看看怎么样
作者: wcy107    时间: 2023-3-26 01:29
f非常帮帮
作者: 寻找星空    时间: 2023-3-26 05:37
1                          
作者: w521521    时间: 2023-3-26 08:31
谢谢楼主,发帖辛苦!
作者: icyjin    时间: 2023-3-26 11:18
希望找个功能扩展更完善!加油
作者: drogan2    时间: 2023-3-26 14:43
让 江小白 来看看帖子里藏了啥好东西~~~
作者: axing116    时间: 2023-3-26 16:44
不要在意这些细节
作者: 无精打采    时间: 2023-3-26 18:55
支持开源~!感谢友哥分享
作者: xcw    时间: 2023-3-26 20:14
        感谢分享,很给力!~
作者: wmsjwmsj    时间: 2023-3-26 22:16
看下 。。。。。。。。。。。。

作者: wmsjwmsj    时间: 2023-3-26 22:18
支持开源~!感谢友哥分享
作者: wmsjwmsj    时间: 2023-3-26 22:19
支持开源~!感谢友哥分享太棒了  正是我想找的
作者: ouding    时间: 2023-3-27 00:10

支持开源~!感谢友哥分享太棒了  正是我想找的
作者: clearlove    时间: 2023-3-27 04:57
比核心库快百倍系列 - 分割文本_快速
作者: simor3    时间: 2023-3-27 08:12
这么厉害,必须要体验一下了
作者: 舞影无踪    时间: 2023-3-27 09:24
要在意这些细节
作者: hongsun2016    时间: 2023-3-27 09:47
必须要体验一下了
作者: 土豆要不    时间: 2023-3-27 10:00
标题: ++
6666666666666666666
作者: xiaoxiao2    时间: 2023-3-27 11:08
感谢分享
作者: xh1020    时间: 2023-3-27 11:18
感谢分享
作者: 大大大路    时间: 2023-3-27 11:47
要在意这些细节
作者: wang2lang    时间: 2023-3-27 11:55
C++源码还是易语言源码?




欢迎光临 精易论坛 (https://125.confly.eu.org/) Powered by Discuz! X3.4