* Dmitry Simonenko <[email protected]> [12/08/14 20:05]:

> diff --git a/include/util.h b/include/util.h
> index e438e95..7cbfa1d 100644
> --- a/include/util.h
> +++ b/include/util.h
> @@ -27,6 +27,7 @@
>   */
>  #include "config.h"
>  
> +#include <string.h>
>  #include <unistd.h>
>  #include <inttypes.h>

What do you need this change for?
  
> diff --git a/mod/box/box_lua.m b/mod/box/box_lua.m
> index 654884f..abb136c 100644
> +static void
> +lbox_pushtuple(struct lua_State *L, struct tuple *tuple);
> +
> +/**
> + * Tuple transforming function.
> + *
> + * Removes the fields designated by 'offset' and 'len' from an tuple,
> + * and replaces them with the elements of supplied data fields,
> + * if any.
> + *
> + * Function returns newly allocated tuple.
> + * It does not change any parent tuple data.
> + *
> + */

It's considered good style by some, including me, to
use present tense, imperative mood in code comments, when
describing what a function does. 

E.g. check this book out:

http://shop.oreilly.com/product/0790145305770.do

It's available online:

http://books.google.ru/books?id=ifhpFdraIkQC&printsec=frontcover&hl=ru#v=onepage&q&f=false

Extract: 

--
Do not use first person. For example, do not say 'Here we display
a list of customers.' Use present tense for comments that
describe a code block, and use imperative mood to describe the
action within that code block.
--

http://books.google.ru/books?id=ifhpFdraIkQC&printsec=frontcover&hl=ru#v=onepage&q&f=false

Finally, the comment, apparently, is outdated.

Here's how I think this comment should look like:
/**
 * Given a tuple, range of fields to remove (start and end field
 * numbers), and a list of fields to paste, calculate the size of
 * the resulting tuple.
 * @param L    lua stack, contains a list of arguments to paste
 * @param start offset in the lua stack where paste arguments
 *              start       
 * @param tuple  old tuple
 * @param offset cut field offset
 * @param len    how many fields to cut
 * @param[out] left size of the left part
 * @param[out] right size of the right part
 * @return size of the new tuple
 */
 
> +static size_t
> +transform_calculate(struct lua_State *L, struct tuple *tuple, int start,
> +                 int argc,
> +                 int offset, int len,
> +                 size_t *left,
> +                 size_t *right)

Style: arguments need to be aligned at the start of the opening
bracket.

We usually don't put each argument on its own line.

> +{
> +     /* calculating size of the new tuple */

Imperative mood, please.

> +     *left = tuple_sizeof(tuple, 0, offset);

I believe tuple_sizeof should take a start pointer as the second
argument, not a field number. This would save a bit of CPU
on the second call.

tuple_range_size, I think, would be a better name.

It's perhaps worth making this function inline.

> +     /* calculating sizes of supplied fields */
> +     size_t middle = 0;
> +     for (int i = start ; i <= argc ; i++) {
> +             size_t field_size = lua_objlen(L, i + 1);
> +             middle += varint32_sizeof(field_size) + field_size;
> +     }

Why do you put i at 'start', and then use i+1 in the loop?
This looks confusing, isn't it better to make sure 
all input parameters are in line so that the loop
can run smoothly?

> +     /* calculating last part of the tuple fields */
> +     *right = tuple_sizeof(tuple, offset + len,
> +                           tuple->field_count - offset + len);
> +     return *left + middle + *right;
> +}
> +

> +static int
> +transform(struct lua_State *L, struct tuple *tuple, int start,
> +      int argc,
> +      int offset, int len)

Style.

> +{
> +     /* validating offset and len */
> +     if (offset < 0) {
> +             if (-offset > tuple->field_count)
> +                     luaL_error(L, "tuple.transform(): offset is out of 
> bound");
> +             offset += tuple->field_count;
> +     } else if (offset > tuple->field_count) {
> +             offset = tuple->field_count;
> +     }
> +     if (len < 0)
> +             luaL_error(L, "tuple.transform(): len is negative");
> +     if (len > tuple->field_count - offset)
> +             len = tuple->field_count - offset;

It seems you can't clearly separate input validation
and the transform itself between lbox_tuple_transform()
and transform(), so I would simply merge these two functions in
one.

> +     /* calculating size of the new tuple */
> +     size_t left = 0, right = 0;

Why initialize variables if you are going to
assign them later on? 

In fact, I would use an array.
size_t sz[2];  -- less pointer arithmetics and less arguments
to pass around.

> +     size_t size = transform_calculate(L, tuple, start, argc, offset, len,
> +                                       &left,
> +                                       &right);
> +     /* allocating new tuple */
> +     struct tuple *dest = tuple_alloc(size);
> +     dest->field_count = (tuple->field_count - len) +
> +                         (argc - (start - 1));
> +     /* constructing tuple */
> +     if (left) {
> +             memcpy(dest->data, tuple->data, left);
> +     }
> +     size_t off = left;
> +     for (int i = start ; i <= argc ; i++) {
> +             size_t field_size = 0;
> +             const char *field = luaL_checklstring(L, i + 1, &field_size);
> +             save_varint32(dest->data + off, field_size);
> +             off += varint32_sizeof(field_size);
> +             memcpy(dest->data + off, field, field_size); 
> +             off += field_size;
> +     }

If you use a pointer instead of offset for dst data in the loop,
instead of size_t off, you have one less instruction per loop for
the code to do (evaluating dest->data + off).

Here you also start from i = start, yet use i + 1 inside the loop.
I think it's less clear and less efficient.

> +     if (right) {
> +             memcpy(dest->data + off,
> +                    tuple_field(tuple, offset + len),
> +                    right);
> +     }

memcpy already checks for zero copy length, an extra check for 
left or right is redundant.

http://stackoverflow.com/questions/3751797/can-i-call-memcpy-and-memmove-with-number-of-bytes-set-to-zero

> +static int
> +tuple_find(struct lua_State *L, struct tuple *tuple,
> +        const char *key,
> +        size_t key_size, bool first)
> +{
> +     u8 *field = tuple->data;
> +     int fieldno = 0;
> +     int count = 0;
> +     while (fieldno < tuple->field_count) {
> +             size_t len = load_varint32((void **) &field);
> +             if (len == key_size && (memcmp(field, key, len) == 0)) {
> +                     lua_pushinteger(L, fieldno);
> +                     count++;
> +                     if (first)
> +                             break;
> +             }
> +             field += len;
> +             fieldno++;
> +     }
> +     return count;
> +}

You can rewrite this function to not use neither field_no nor
count. Break the loop when field >= tuple->data + tuple->bsize.
Save the stack top at the beginning, and return the diff.

Otherwise the patch looks pretty nice, thank you for writing it!

-- 
kostja

_______________________________________________
Mailing list: https://launchpad.net/~tarantool-developers
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~tarantool-developers
More help   : https://help.launchpad.net/ListHelp

Reply via email to