diff options
Diffstat (limited to 'winsup/cygwin/local_includes/vstrlist.h')
-rw-r--r-- | winsup/cygwin/local_includes/vstrlist.h | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/winsup/cygwin/local_includes/vstrlist.h b/winsup/cygwin/local_includes/vstrlist.h new file mode 100644 index 000000000..d5ad717c3 --- /dev/null +++ b/winsup/cygwin/local_includes/vstrlist.h @@ -0,0 +1,373 @@ +/* vstrlist.h: class vstrlist + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifdef __cplusplus + +struct allocator_interface +{ + virtual void * alloc (size_t) = 0; + virtual void free (void *) = 0; +}; + + +/* The allocated_type makes sure to use the free () method of the + same allocator_interface than the alloc () method was used of. + + Stores the allocator_interface address before the real object, + to hide it from (construction & destruction of) real object. */ +class allocated_type +{ + union allocator_store + { + allocator_interface * allocator_; + char alignment_[8]; + + union pointer + { + void * vptr; + allocator_store * real; + }; + }; + +public: + void * operator new (size_t class_size, allocator_interface & allocator) + { + allocator_store::pointer astore; + astore.vptr = allocator.alloc (sizeof (allocator_store) + class_size); + astore.real->allocator_ = &allocator; + ++ astore.real; + return astore.vptr; + } + + void operator delete (void * p) + { + allocator_store::pointer astore; + astore.vptr = p; + -- astore.real; + astore.real->allocator_->free (astore.vptr); + } +}; + + +/* Double linked list of char arrays, each being a string buffer, + which's final buffer size and initial string content is defined + by a NULL terminated variable argument list of STRING+LEN pairs, + where each STRING (up to LEN) is concatenated for the initial + string buffer content, and each LEN is added to the final size + of the allocated string buffer. + If LEN is -1, strlen(STRING) is used for LEN. + + Needs: + An implementation of the allocator_interface. + + Provides: + iterator: + short name for the string_iterator + string_iterator: + provides readonly access via member methods: + string (): readonly string buffer + stringlength (): length (readonly) of initial string + buffer_iterator: + extends string_iterator + provides writeable access via member methods: + buffer (): writeable string buffer + bufferlength (): length (readonly) of allocated buffer + + Usage sample: + char * text = "snipe"; + vstrlist l; + l.appendv (text, 4, text+3, 2, "", 2, NULL); + buffer_iterator it (l.begin ()); + strcpy (it->buffer () + it->stringlength (), "ts"); + printf ("Sample result is: '%s'", it->string ()); + Sample result is: 'snippets' */ +class vstrlist +{ +public: + class member + : public allocated_type + { + friend class vstrlist; + friend class string_iterator; + + member * prev_; + member * next_; + size_t bufferlength_; + size_t stringlength_; + char buffer_[1]; /* we always have space for the trailing zero */ + + /* no copy, just swap */ + member (member const &); + member & operator = (member const &); + + /* anchor */ + void * operator new (size_t class_size, allocator_interface & allocator) + { + return allocated_type::operator new (class_size, allocator); + } + + /* anchor */ + member () + : allocated_type () + , prev_ (this) + , next_ (this) + , bufferlength_ (0) + , stringlength_ (0) + , buffer_ () + {} + + /* entry: determine memory size from args */ + void * operator new (size_t class_size, allocator_interface & allocator, + char const * part0, va_list parts) + { + char const * part = part0; + va_list partsdup; + va_copy (partsdup, parts); + while (part) + { + int partlen = va_arg (partsdup, int); + if (partlen < 0) + partlen = strlen (part); + class_size += partlen; + part = va_arg (partsdup, char const *); + } + va_end (partsdup); + + return allocated_type::operator new (class_size, allocator); + } + + /* entry: instantly insert into list */ + member (member * before, char const * part0, va_list parts) + : allocated_type () + , prev_ (NULL) + , next_ (NULL) + , bufferlength_ (0) + , stringlength_ () + , buffer_ () + { + prev_ = before->prev_; + next_ = before; + + prev_->next_ = this; + next_->prev_ = this; + + char * dest = buffer_; + char const * part = part0; + va_list partsdup; + va_copy (partsdup, parts); + while (part) + { + int partlen = va_arg (partsdup, int); + if (partlen < 0) + { + char * old = dest; + dest = stpcpy (old, part); + partlen = dest - old; + } + else + dest = stpncpy (dest, part, partlen); + bufferlength_ += partlen; + part = va_arg (partsdup, const char *); + } + va_end (partsdup); + *dest = (char)0; + stringlength_ = dest - buffer_; + if (bufferlength_ > stringlength_) + memset (++dest, 0, bufferlength_ - stringlength_); + } + + /* remove entry from list */ + ~member () + { + member * next = next_; + member * prev = prev_; + if (next) + next->prev_ = prev; + if (prev) + prev->next_ = next; + prev_ = NULL; + next_ = NULL; + } + + public: + member const * next () const { return next_; } + member * next () { return next_; } + member const * prev () const { return next_; } + member * prev () { return next_; } + + /* readonly access */ + char const * string () const { return buffer_; } + size_t stringlength () const { return stringlength_; } + + /* writeable access */ + char * buffer () { return buffer_; } + size_t bufferlength () { return bufferlength_; } + }; + + /* readonly access */ + class string_iterator + { + friend class vstrlist; + friend class buffer_iterator; + + member * current_; + + string_iterator (); + + string_iterator (member * current) + : current_ (current) + {} + + public: + string_iterator (string_iterator const & rhs) + : current_ (rhs.current_) + {} + + string_iterator & operator = (string_iterator const & rhs) + { + current_ = rhs.current_; + return *this; + } + + string_iterator & operator ++ () + { + current_ = current_->next (); + return *this; + } + + string_iterator operator ++ (int) + { + string_iterator ret (*this); + current_ = current_->next (); + return ret; + } + + string_iterator & operator -- () + { + current_ = current_->prev (); + return *this; + } + + string_iterator operator -- (int) + { + string_iterator ret (*this); + current_ = current_->prev (); + return ret; + } + + bool operator == (string_iterator const & rhs) const + { + return current_ == rhs.current_; + } + + bool operator != (string_iterator const & rhs) const + { + return current_ != rhs.current_; + } + + /* readonly member access */ + member const & operator * () const { return *current_; } + member const * operator -> () const { return current_; } + + void remove () + { + member * old = current_; + ++ *this; + delete old; + } + }; + + /* writeable access */ + class buffer_iterator + : public string_iterator + { + public: + explicit /* can be used with vstrlist.begin () */ + buffer_iterator (string_iterator const & begin) + : string_iterator (begin) + {} + + buffer_iterator (buffer_iterator const & rhs) + : string_iterator (rhs) + {} + + buffer_iterator & operator = (buffer_iterator const & rhs) + { + string_iterator::operator = (rhs); + return *this; + } + + /* writeable member access */ + member & operator * () const { return *current_; } + member * operator -> () const { return current_; } + }; + +private: + allocator_interface & allocator_; + member * anchor_; + + /* not without an allocator */ + vstrlist (); + + /* no copy, just swap () */ + vstrlist (vstrlist const &); + vstrlist & operator = (vstrlist const &); + +public: + /* iterator is the string_iterator */ + typedef class string_iterator iterator; + + iterator begin () { return iterator (anchor_->next ()); } + iterator end () { return iterator (anchor_ ); } + iterator rbegin () { return iterator (anchor_->prev ()); } + iterator rend () { return iterator (anchor_ ); } + + vstrlist (allocator_interface & a) + : allocator_ (a) + , anchor_ (NULL) /* exception safety */ + { + anchor_ = new (allocator_) member (); + } + + ~vstrlist () + { + if (anchor_ != NULL) + { + for (iterator it = begin (); it != end (); it.remove ()); + delete anchor_; + } + } + + void swap (vstrlist & that) + { + allocator_interface & a = allocator_; + member * m = anchor_; + allocator_ = that.allocator_; + anchor_ = that.anchor_; + that.allocator_ = a; + that.anchor_ = m; + } + + string_iterator appendv (char const * part0, va_list parts) + { + member * ret = new (allocator_, part0, parts) + member (anchor_, part0, parts); + return string_iterator (ret); + } + + string_iterator appendv (char const * part0, ...) + { + va_list parts; + va_start (parts, part0); + string_iterator ret = appendv (part0, parts); + va_end (parts); + return ret; + } +}; + +#endif /* __cplusplus */ |