On Thu, Aug 11, 2016 at 09:18:34PM +0900, Oleg Endo wrote:
> On Wed, 2016-08-10 at 21:31 -0400, Trevor Saunders wrote:
> 
> > 
> > Well, I'd say the compromises made in std::string make it pretty
> > terrible for general purpose use accept where perf and memory doesn't
> > matter at all.
> > 
> > std::vector isn't very great size wise either, imho the size / 
> > capacity fields would be much better put in the buffer than in the 
> > struct itself, to save 2 * sizeof (void *) in sizeof std::vector.
> 
> There's nothing in the standard that says those fields have to go into
> the vector struct/class itself and not into the data buffer.  It just
> happens to be the way it's implemented in libstdc++.  E.g. libc++
> implements some things in different ways to save a few bytes here and
> there.
> 
> It looks more practical to put those fields into the container itself,
> otherwise you'd have to do a nullptr check every time you access the
> size field etc.  Although newer compilers optimize away the redundant
> nullptr checks, older compilers (which GCC wants to be good with) might
> not do it.  In any case, it seems to generate slightly bigger code, at
> least in one instance (see attachment).

if you are clever you can have a empty global vector that you point all
the empty vectors at and so eliminate the null check.  Well, I guess
that doesn't work quite as well if the global needs to be accessed
through a plt sigh, but at least you only need to check against it for
reallocation which is rather heavy weight anyway.

> Anyway, normally there is more data in the vectors than there are
> vectors around, so whether sizeof (vector) is 8 or 24 bytes doesn't
> matter.

It matters if you have any empty vectors around.  The only numbers I can
find are https://bugzilla.mozilla.org/show_bug.cgi?id=1007846 but I seem
to remember seeing that for Firefox at least most vectors contained 0
elements.

> > 
> > or just having your stack_string type convert to the normal string 
> > type so that you can pass mutable references.
> 
> But that would imply copying, wouldn't it?

Not if you are clever, you can use the same trick gcc uses in vec /
auto_vec with strings.

Trev

> 
> Cheers,
> Oleg

> 
> #if 0
> template <typename T>
> class vector
> {
> public:
>   unsigned int size (void) const { return m_buffer != nullptr ? 
> m_buffer->size : 0; }
>   bool empty (void) const { return size () == 0; }
> 
>   unsigned int capacity (void) const { return m_buffer != nullptr ? 
> m_buffer->capacity : 0; }
> 
>   T* data (void) { return (T*)(m_buffer + 1); }
>   const T* data (void) const { return (const T*)(m_buffer + 1); }
> 
>   T& operator [] (unsigned int i) { return data ()[i]; }
>   const T& operator [] (unsigned int i) const { return data ()[i]; }
> 
> private:
>   struct buffer_header
>   {
>     unsigned int size;
>     unsigned int capacity;
>   };
> 
>   buffer_header* m_buffer;
> };
> 
> 
> int foo (const vector<int>& x)
> {
>   if (x.empty ())
>     return 0;
> 
>   int r = 0;
>   for (unsigned int i = 0; i < x.size (); ++i)
>     r += x[i];
> 
>   return r;
> }
> 
> /*
> -O2 -m2a
>       mov.l   @r4,r2
>       tst     r2,r2
>       bt      .L5
>       mov.l   @r2,r1
>       tst     r1,r1
>       bt.s    .L5
>       shll2   r1
>       add     #-4,r1
>       shlr2   r1
>       add     #8,r2
>       mov     #0,r0
>       add     #1,r1
>       .align 2
> .L3:
>       mov.l   @r2+,r3
>       dt      r1
>       bf.s    .L3
>       add     r3,r0
>       rts/n
>       .align 1
> .L5:
>       rts
>       mov     #0,r0
> */
> #endif
> 
> 
> #if 1
> 
> template <typename T>
> class vector
> {
> public:
>   unsigned int size (void) const { return m_size; }
>   bool empty (void) const { return size () == 0; }
> 
>   unsigned int capacity (void) const { return m_capacity; }
> 
>   T* data (void) { return (T*)(m_buffer); }
>   const T* data (void) const { return (const T*)(m_buffer); }
> 
>   T& operator [] (unsigned int i) { return data ()[i]; }
>   const T& operator [] (unsigned int i) const { return data ()[i]; }
> 
> private:
>   unsigned int m_size;
>   unsigned int m_capacity;
>   T* m_buffer;
> };
> 
> 
> int foo (const vector<int>& x)
> {
>   if (x.empty ())
>     return 0;
> 
>   int r = 0;
>   for (unsigned int i = 0; i < x.size (); ++i)
>     r += x[i];
> 
>   return r;
> }
> 
> /*
> -O2 -m2a
>       mov.l   @r4,r1
>       tst     r1,r1
>       bt.s    .L7
>       mov     #0,r0
>       shll2   r1
>       mov.l   @(8,r4),r2
>       add     #-4,r1
>       shlr2   r1
>       add     #1,r1
>       .align 2
> .L3:
>       mov.l   @r2+,r3
>       dt      r1
>       bf.s    .L3
>       add     r3,r0
> .L7:
>       rts/n
> */
> 
> #endif
> 

Reply via email to