git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: William <william.duclot@ensimag.grenoble-inp.fr>
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org, simon.rabourg@ensimag.grenoble-inp.fr,
	francois.beutin@ensimag.grenoble-inp.fr,
	antoine.queru@ensimag.grenoble-inp.fr,
	matthieu.moy@grenoble-inp.fr, mhagger@alum.mit.edu
Subject: Re: [PATCH 2/2] strbuf: allow to use preallocated memory
Date: Tue, 31 May 2016 17:45:03 +0200	[thread overview]
Message-ID: <20160531154503.GA24895@Messiaen> (raw)
In-Reply-To: <xmqqbn3m7n25.fsf@gitster.mtv.corp.google.com>

On Mon, May 30, 2016 at 11:34:42PM -0700, Junio C Hamano wrote:
> William Duclot <william.duclot@ensimag.grenoble-inp.fr> writes:
> 
>> The API contract is still respected:
>>
>> - The API users may peek strbuf.buf in-place until they perform an
>>   operation that makes it longer (at which point the .buf pointer
>>   may point at a new piece of memory).
> 
> I think the contract is actually a bit stronger; the API reserves
> the right to free and reallocate a smaller chunk of memory if you
> make the string shorter, so peeked value of .buf will not be relied
> upon even if you didn't make it longer.

Right, anytime the string size change
 
>> - The API users may strbuf_detach() to obtain a piece of memory that
>>   belongs to them (at which point the strbuf becomes empty), hence
>>   needs to be freed by the callers.
> 
> Shouldn't you be honuoring another API contract?
> 
>  - If you allow an instance of strbuf go out of scope without taking
>    the ownership of the string by calling strbuf_detach(), you must
>    release the resource by calling strbuf_release().
> 
> As long as your "on stack strbuf" allows lengthening the string
> beyond the initial allocation (i.e. .alloc, not .len), the user of
> the API (i.e. the one that placed the strbuf on its stack) would not
> know when the implementation (i.e. the code in this patch) decides
> to switch to allocated memory, so it must call strbuf_release()
> before it leaves.  Which in turn means that your implementation of
> strbuf_release() must be prepared to be take a strbuf that still has
> its string on the stack.

Well, my implementation does handle a strbuf that still has its
string on the stack: the buffer won't be freed in this case (only a
reset to STRBUF_INIT).
Unless I misunderstood you?

> On the other hand, if your "on stack strbuf" does not allow
> lengthening, I'd find such a "feature" pretty much useless.  The
> caller must always test the remaining capacity, and switch to a
> dynamic strbuf, which is something the caller would expect the API
> implementation to handle silently.  You obviously do not have to
> release the resource in such a case, but that is being convenient
> in the wrong part of the API.
> 
> It would be wonderful if I can do:
> 
> 	void func (void)
>         {
> 		extern void use(char *[2]);
> 		/*
>                  * strbuf that uses 1024-byte on-stack buffer
>                  * initially, but it may be extended dynamically.
>                  */
> 		struct strbuf buf = STRBUF_INIT_ON_STACK(1024);
> 		char *x[2];
> 
> 		strbuf_add(&buf, ...); /* add a lot of stuff */
>                 x[0] = strbuf_detach(&buf, NULL);
> 		strbuf_add(&buf, ...); /* do some stuff */
>                 x[1] = strbuf_detach(&buf, NULL);
> 		use(x);
> 
>                 strbuf_release(&buf);
> 	}
>
> and add more than 2kb with the first add (hence causing buf to
> switch to dynamic scheme), the first _detach() gives the malloc()ed 
> piece of memory to x[0] _and_ points buf.buf back to the on-stack
> buffer (and buf.alloc back to 1024) while setting buf.len to 0,
> so that the second _add() can still work purely on stack as long as
> it does not go beyond the 1024-byte on-stack buffer. 


I think that it's possible, but extends the API beyond what was
originally intended by Michael. I don't see other use cases than treating
several string sequentially, is it worth avoiding a attach_movable() 
(as suggested by Michael in place of wrap_preallocated())?
You could do:

	void func (void)
    {
		extern void use(char *[2]);
		/*
         * strbuf that uses 1024-byte on-stack buffer
         * initially, but it may be extended dynamically.
         */
        char on_stack[1024];
		struct strbuf buf;
 		char x[2];

        strbuf_attach_movable(&sb, on_stack, 0, sizeof(on_stack));
 		strbuf_add(&buf, ...); /* add a lot of stuff */
        x[0] = strbuf_detach(&buf, NULL);
        strbuf_attach_movable(&sb, on_stack, 0, sizeof(on_stack));
 		strbuf_add(&buf, ...); /* do some stuff */
        x[1] = strbuf_detach(&buf, NULL);
 		use(x);
 
        strbuf_release(&buf);
 	}

Which seems pretty close without needing the strbuf API to remember the
original buffer or to even care about memory being on the stack or the
heap.

>> +/**
>> + * Flags
>> + * --------------
>> + */
>> +#define STRBUF_OWNS_MEMORY 1
>> +#define STRBUF_FIXED_MEMORY (1 << 1)
> 
> This is somewhat a strange way to spell two flag bits.  Either spell
> them as 1 and 2 (perhaps in octal or hexadecimal), or spell them as
> 1 shifted by 0 and 1 to the left.  Don't mix the notation.

Noted

>> @@ -20,16 +28,37 @@ char strbuf_slopbuf[1];
>>  
>>  void strbuf_init(struct strbuf *sb, size_t hint)
>>  {
>> +	sb->flags = 0;
>>  	sb->alloc = sb->len = 0;
>>  	sb->buf = strbuf_slopbuf;
>>  	if (hint)
>>  		strbuf_grow(sb, hint);
>>  }
>>  
>> +void strbuf_wrap_preallocated(struct strbuf *sb, char *path_buf,
>> +			      size_t path_buf_len, size_t alloc_len)
>> +{
>> +	if (!path_buf)
>> +		die("you try to use a NULL buffer to initialize a strbuf");
> 
> What does "path" mean in the context of this function (and its
> "fixed" sibling)?

That should be someting like `str` and `str_len` indeed

  reply	other threads:[~2016-05-31 15:45 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-30 10:36 [PATCH 0/2] strbuf: improve API William Duclot
2016-05-30 10:36 ` [PATCH 1/2] strbuf: add tests William Duclot
2016-05-30 11:26   ` Johannes Schindelin
2016-05-30 13:42     ` Simon Rabourg
2016-05-30 11:56   ` Matthieu Moy
2016-05-31  2:04   ` Michael Haggerty
2016-05-31  9:48     ` Simon Rabourg
2016-05-30 10:36 ` [PATCH 2/2] strbuf: allow to use preallocated memory William Duclot
2016-05-30 12:13   ` Johannes Schindelin
2016-05-30 13:20     ` William Duclot
2016-05-31  6:21       ` Johannes Schindelin
2016-05-31  3:05     ` Michael Haggerty
2016-05-31  6:41       ` Johannes Schindelin
2016-05-31  8:25         ` Michael Haggerty
2016-05-30 12:52   ` Matthieu Moy
2016-05-30 14:15     ` William Duclot
2016-05-30 14:34       ` Matthieu Moy
2016-05-30 15:16         ` William Duclot
2016-05-31  4:05     ` Michael Haggerty
2016-05-31 15:59       ` William Duclot
2016-06-03 14:04       ` William Duclot
2016-05-30 21:56   ` Mike Hommey
2016-05-30 22:46     ` William Duclot
2016-05-30 22:50       ` Mike Hommey
2016-05-31  6:34   ` Junio C Hamano
2016-05-31 15:45     ` William [this message]
2016-05-31 15:54       ` Matthieu Moy
2016-05-31 16:08         ` William Duclot
2016-05-30 11:32 ` [PATCH 0/2] strbuf: improve API Remi Galan Alfonso
2016-06-01  7:42   ` Jeff King
2016-06-01 19:50     ` David Turner
2016-06-01 20:09       ` Jeff King
2016-06-01 20:22         ` David Turner
2016-06-01 21:07     ` Jeff King
2016-06-02 11:11       ` Michael Haggerty
2016-06-02 12:58         ` Matthieu Moy
2016-06-02 14:22           ` William Duclot
2016-06-24 17:20         ` Jeff King

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160531154503.GA24895@Messiaen \
    --to=william.duclot@ensimag.grenoble-inp.fr \
    --cc=antoine.queru@ensimag.grenoble-inp.fr \
    --cc=francois.beutin@ensimag.grenoble-inp.fr \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=matthieu.moy@grenoble-inp.fr \
    --cc=mhagger@alum.mit.edu \
    --cc=simon.rabourg@ensimag.grenoble-inp.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).