优化这个功能?

时间:2014-04-05 00:35:45

标签: c++ v8

我已编写此代码(使用V8库)。我经历了几次,这感觉就像是我写这样的东西的唯一方式。该函数的目的是替换JavaScript .split()函数;因为当使用具有限制的函数时,不包括返回数组中数组的最后部分。 EG:

var str = "Test split string with limit";
var out = str.split(' ', 2);

数组out将包含:[Testsplit]。我希望它包含:[Testsplitstring with limit]。

我知道有一些纯粹的JS方法可以做到这一点但是我发现它们比单个C ++绑定调用更糟糕,可能更慢(?)。

这是我的功能:

/**
 * Explodes a string but limits the tokens
 * @param input
 * @param delim
 * @param limit
 * @return
 */
void ASEngine::Engine::ASstrtok(const v8::FunctionCallbackInfo<v8::Value>& args)
{
    Assert(3, args);

    Isolate* isolate = args.GetIsolate();

    /* Get args */
    String::Utf8Value a1(args[0]);
    String::Utf8Value a2(args[1]);
    Local<Uint32> a3 = args[2]->ToUint32();

    std::string input  = std::string(*a1);
    std::string delim  = std::string(*a2);
    unsigned int limit = a3->Int32Value();

    unsigned int inputLen = input.length();

    // Declare a temporary array to shove into the return later
    std::vector<char*> tmp;
    tmp.reserve(limit);

    unsigned int delimlen = delim.length();
    char* cp = (char*) malloc(inputLen);
    char* cursor = cp + inputLen; // Cursor
    char* cpp = (char*) cp; // Keep the start of the string

    // Copy the haystack into a modifyable char ptr
    memset(cp + inputLen, 0x00, 1);
    memcpy(cp, input.c_str(), inputLen);

    unsigned int arrayIndex = 0;
    for(unsigned int i=0;i<limit;i++)
    {
        if((cursor = strstr(cp, delim.c_str())) == NULL)
        {
            cursor = (char*) cpp + inputLen;
            break;
        }

        for(int j=0;j<delimlen;j++)
            *(cursor+j) = 0x00;

        tmp.push_back(cp);

        cp = cursor + delimlen;
        arrayIndex++;
    }
    if(*(cp) != '\0')
    {
        arrayIndex++;
        tmp.push_back(cp);
    }

    Handle<Array> rtn = Array::New(args.GetIsolate(), arrayIndex);

    /* Loop through the temporary array and assign
       the variables to the V8 array */
    for(unsigned int i=0;i<arrayIndex;i++)
    {
        rtn->Set(i, String::NewFromUtf8(
            isolate, tmp[i], String::kNormalString, strlen(tmp[i])
        ));
    }

    /* Clean up memory */
    delete cpp;
    cp      = NULL;
    cpp     = NULL;
    cursor  = NULL;
    isolate = NULL;

    /* Set the return */
    args.GetReturnValue().Set(rtn);
}

如果你想知道:变量cpp就在那里我可以在完成后删除字符指针(因为调用v8&#39; s String::NewFromUtf8()函数复制字符串)并且我修改了在函数的过程中指针cp

1 个答案:

答案 0 :(得分:1)

在优化之前,我会修复代码以使其正确。

char* cp = (char*) malloc(inputLen);
... 

/* Clean up memory */
delete cpp;

虽然在某些实现中,newmalloc执行的操作完全相同,但其他实现却没有。因此,如果您使用malloc分配,请使用free释放内存,而不是delete

如果你想要聪明一点,我希望:

tmp.reserve(limit+1);

将确保您为字符串的其余部分留出空间,而无需在向量中进一步分配。

由于循环后未使用cursor,因此将其设置在打破循环的if内是没有意义的。

    if((cursor = strstr(cp, delim.c_str())) == NULL)
    {
        cursor = (char*) cpp + inputLen;
        break;
    }

您在不需要它的地方使用强制转换(char *),例如:

char* cpp = (char*) cp; // Keep the start of the string

cp已经是char *

此:

memset(cp + inputLen, 0x00, 1);

与:

相同
cp[inputlen] = 0; 

但除非编译器内联memset,否则要快得多。

Likewsie:

*(cursor+j) = 0x00;

可写:

cursor[j] = 0; 

但是,假设delimLen大于1,您可以放弃:

    for(int j=0;j<delimlen;j++)
        *(cursor+j) = 0x00;

转换为:

  *cursor = 0; 

因为您的新cp值无论如何都会跳过delimlen以上。

这些绝对没有用处:

cp      = NULL;
cpp     = NULL;
cursor  = NULL;
isolate = NULL;

不幸的是,我希望你的函数中的大部分时间都不会出现在我评论过的任何代码中。但是在调用JS库和本机C ++代码之间来回传递参数。如果你在JS中编写相同的代码,我会感到惊讶。 (当涉及到速度时,上述所有都没有太大的区别,它只是正确性和“如果编译器相当愚蠢”,“少量可能浪费的周期”)。