Open-RJ C/C++ User's Journal Synesis Software STLSoft - ... Robust, Lightweight, Cross-platform, Template Software ...

openrj/stl/record.hpp

Go to the documentation of this file.
00001 /* /////////////////////////////////////////////////////////////////////////////
00002  * File:    openrj/stl/record.hpp
00003  *
00004  * Purpose: record class, in the STL mapping of the Open-RJ library
00005  *
00006  * Created: 15th June 2004
00007  * Updated: 28th May 2006
00008  *
00009  * Home:    http://openrj.org/
00010  *
00011  * Copyright (c) 2004-2006, Matthew Wilson and Synesis Software
00012  * All rights reserved.
00013  *
00014  * Redistribution and use in source and binary forms, with or without
00015  * modification, are permitted provided that the following conditions are met:
00016  *
00017  * - Redistributions of source code must retain the above copyright notice, this
00018  *   list of conditions and the following disclaimer.
00019  * - Redistributions in binary form must reproduce the above copyright notice,
00020  *   this list of conditions and the following disclaimer in the documentation
00021  *   and/or other materials provided with the distribution.
00022  * - Neither the names of Matthew Wilson and Synesis Software nor the names of
00023  *   any contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00027  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00029  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00030  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00031  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00032  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00035  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00036  * POSSIBILITY OF SUCH DAMAGE.
00037  *
00038  * ////////////////////////////////////////////////////////////////////////// */
00039 
00040 
00046 #ifndef OPENRJ_INCL_OPENRJ_STL_HPP_RECORD
00047 #define OPENRJ_INCL_OPENRJ_STL_HPP_RECORD
00048 
00049 /* /////////////////////////////////////////////////////////////////////////////
00050  * Version information
00051  */
00052 
00053 #ifndef OPENRJ_DOCUMENTATION_SKIP_SECTION
00054 # define OPENRJ_VER_OPENRJ_STL_HPP_RECORD_MAJOR     1
00055 # define OPENRJ_VER_OPENRJ_STL_HPP_RECORD_MINOR     7
00056 # define OPENRJ_VER_OPENRJ_STL_HPP_RECORD_REVISION  4
00057 # define OPENRJ_VER_OPENRJ_STL_HPP_RECORD_EDIT      28
00058 #endif /* !OPENRJ_DOCUMENTATION_SKIP_SECTION */
00059 
00060 /* /////////////////////////////////////////////////////////////////////////////
00061  * Includes
00062  */
00063 
00064 #include <openrj/openrj.h>
00065 #include <openrj/openrj_assert.h>
00066 
00067 #if defined(ORJ_NO_EXCEPTIONS)
00068 # error The Open-RJ STL mapping is not compilable in the absence of exception
00069 #endif /* ORJ_NO_EXCEPTIONS */
00070 
00071 #include <openrj/stl/field.hpp>
00072 
00073 #include <algorithm>
00074 #include <iterator>
00075 #include <stdexcept>
00076 
00077 #include <stlsoft/iterators/indirect_reverse_iterator.hpp>
00078 #include <stlsoft/iterator.hpp>
00079 
00080 /* /////////////////////////////////////////////////////////////////////////////
00081  * Compiler warnings
00082  */
00083 
00084 #ifdef __BORLANDC__
00085 # pragma warn -8027
00086 #endif /* __BORLANDC__ */
00087 
00088 /* /////////////////////////////////////////////////////////////////////////////
00089  * Namespace
00090  */
00091 
00092 namespace openrj
00093 {
00094 
00095 namespace stl
00096 {
00097 
00098 /* /////////////////////////////////////////////////////////////////////////////
00099  * Classes
00100  */
00101 
00103 class record
00104 {
00105 public:
00107     typedef record                                          class_type;
00109     typedef field                                           value_type;
00111     typedef value_type const                                const_reference;
00113     typedef value_type const                                *const_pointer;
00115     typedef ptrdiff_t                                       difference_type;
00116 
00117 #ifndef OPENRJ_DOCUMENTATION_SKIP_SECTION
00118 public:
00119     class const_iterator;
00120 
00121     friend class const_iterator;
00122 #endif /* !OPENRJ_DOCUMENTATION_SKIP_SECTION */
00123 
00124 #if defined(__STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT)
00126 #  if 0
00127     typedef stlsoft_ns_qual(const_reverse_iterator_base)<   const_iterator
00128                                                         ,   value_type
00129                                                         ,   value_type
00130                                                         ,   void
00131                                                         ,   difference_type
00132                                                         >   const_reverse_iterator;
00133 #  else /* ? 0 */
00134     // Can't use reverse_iterator, because const_iterator is a forward-declared member 
00135     // class - this now appears incorrect. Somehow I've made subsequent changes that
00136     // nullify the requirement. TODO: Investigate further ...
00137     typedef stlsoft_ns_qual(indirect_reverse_iterator)<     const_iterator
00138                                                         ,   value_type
00139                                                         ,   value_type // Return by value!
00140                                                         ,   void
00141                                                         ,   difference_type
00142                                                         ,   stlsoft_ns_qual_std(random_access_iterator_tag)
00143                                                         >   const_reverse_iterator;
00144 #  endif /* 0 */
00145 #endif /* __STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT */
00146 
00147 public:
00149     explicit record(ORJRecord const *record);
00151     record();
00153     record(record const &rhs);
00154 
00156     record &operator =(record const &rhs);
00157 
00158 public:
00160     size_t size() const;
00161 
00163     bool empty() const;
00164 
00166     string_t comment() const;
00167 
00174     const field operator [](size_t index) const;
00175 
00177     bool has_field(string_t const &name) const;
00178 
00179 #if defined(STLSOFT_COMPILER_IS_INTEL)
00180     bool has_field(char const *name) const
00181     {
00182         return this->has_field(string_t(name));
00183     }
00184 #endif /* compiler */
00185 
00186 #if 0
00188     bool has_field(string_t const &name, string_t const &value) const;
00189 #endif /* 0 */
00190 
00192     size_t count_fields(string_t const &name) const;
00193 
00200     const string_t operator [](string_t const &name) const; // throw (std::out_of_range)
00201 
00202 #if defined(STLSOFT_COMPILER_IS_INTEL)
00203     const string_t operator [](char const *name) const
00204     {
00205         return this->operator [](string_t(name));
00206     }
00207 #endif /* compiler */
00208 
00216     string_t get_field_value(string_t const &name, string_t const &defValue) const;
00217 
00218 public:
00222     const_iterator begin() const;
00226     const_iterator end() const;
00227 
00228 #if defined(__STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT)
00232     const_reverse_iterator rbegin() const;
00236     const_reverse_iterator rend() const;
00237 #endif /* __STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT */
00238 
00239 private:
00248     struct same_name;
00249 
00250 private:
00251     static field create_field_(ORJFieldA const *r)
00252     {
00253         return field(r);
00254     }
00255 
00256     ORJField const  *find_field_(string_t const &name) const;
00257 //    ORJField const  *find_field_(string_t const &name, string_t const &value) const;
00258     size_t          count_fields_(string_t const &name) const;
00259 
00260 private:
00261     ORJRecord const *m_record;
00262     size_t          m_flags;
00263 };
00264 
00265 class record::const_iterator
00266     : public stlsoft::iterator_base<std::random_access_iterator_tag, const record::value_type, record::difference_type, record::const_pointer, record::const_reference>
00267 {
00268 public:
00269     typedef field   value_type;
00270 
00271 private:
00272     friend class    record;
00273 
00274     const_iterator(ORJFieldA const *field);
00275 public:
00276     const_iterator();
00277     const_iterator(const_iterator const &rhs);
00278     const_iterator &operator =(const_iterator const &rhs);
00279 
00280 public:
00281 #ifdef OPENRJ_STL_ITERATOR_HOLDS_VALUE
00282     const_reference operator *() const;
00283 #else /* ? OPENRJ_STL_ITERATOR_HOLDS_VALUE */
00284     value_type operator *() const;
00285 #endif /* OPENRJ_STL_ITERATOR_HOLDS_VALUE */
00286     const_iterator &operator ++();
00287     const_iterator operator ++(int);
00288     const_iterator &operator --();
00289     const_iterator operator --(int);
00290 
00291 public:
00292     const_iterator operator -(difference_type d) const;
00293     difference_type operator -(const_iterator const &rhs) const;
00294 
00295 public:
00296     bool is_equal(const_iterator const &rhs) const;
00297 
00298 #if defined(STLSOFT_COMPILER_IS_BORLAND) || \
00299     defined(STLSOFT_COMPILER_IS_DMC)
00300     bool operator ==(const_iterator const &rhs) const;
00301     bool operator !=(const_iterator const &rhs) const;
00302 #endif /* compiler */
00303 
00304 private:
00305     ORJFieldA const     *m_field;
00306 #ifdef OPENRJ_STL_ITERATOR_HOLDS_VALUE
00307     mutable value_type  m_value;
00308 #endif /* OPENRJ_STL_ITERATOR_HOLDS_VALUE */
00309 };
00310 
00311 /* /////////////////////////////////////////////////////////////////////////////
00312  * Operators
00313  */
00314 
00315 #if !defined(__BORLANDC__) && \
00316     !defined(__DMC__)
00317 inline bool operator ==(record::const_iterator const &lhs, record::const_iterator const &rhs)
00318 {
00319     return lhs.is_equal(rhs);
00320 }
00321 
00322 inline bool operator !=(record::const_iterator const &lhs, record::const_iterator const &rhs)
00323 {
00324     return !lhs.is_equal(rhs);
00325 }
00326 #endif /* compiler */
00327 
00328 /* /////////////////////////////////////////////////////////////////////////////
00329  * Implementation
00330  */
00331 
00332 // record::const_iterator
00333 
00334 inline record::const_iterator::const_iterator(ORJFieldA const *field)
00335     : m_field(field)
00336 {}
00337 
00338 inline record::const_iterator::const_iterator()
00339     : m_field(NULL)
00340 {}
00341 
00342 inline record::const_iterator::const_iterator(const_iterator const &rhs)
00343     : m_field(rhs.m_field)
00344 {}
00345 
00346 inline record::const_iterator &record::const_iterator::operator =(const_iterator const &rhs)
00347 {
00348     m_field = rhs.m_field;
00349 
00350     return *this;
00351 }
00352 
00353 #ifdef OPENRJ_STL_ITERATOR_HOLDS_VALUE
00354 inline record::const_reference record::const_iterator::operator *() const
00355 {
00356     m_value = value_type(m_field);
00357 
00358     return m_value;
00359 #else /* ? OPENRJ_STL_ITERATOR_HOLDS_VALUE */
00360 inline record::value_type record::const_iterator::operator *() const
00361 {
00362     return create_field_(m_field);
00363 #endif /* OPENRJ_STL_ITERATOR_HOLDS_VALUE */
00364 }
00365 
00366 inline record::const_iterator &record::const_iterator::operator ++()
00367 {
00368     ++m_field;
00369 
00370     return *this;
00371 }
00372 
00373 inline record::const_iterator record::const_iterator::operator ++(int)
00374 {
00375     const_iterator  ret(*this);
00376 
00377     operator ++();
00378 
00379     return ret;
00380 }
00381 
00382 inline record::const_iterator &record::const_iterator::operator --()
00383 {
00384     --m_field;
00385 
00386     return *this;
00387 }
00388 
00389 inline record::const_iterator record::const_iterator::operator --(int)
00390 {
00391     const_iterator  ret(*this);
00392 
00393     operator --();
00394 
00395     return ret;
00396 }
00397 
00398 inline record::const_iterator record::const_iterator::operator -(record::difference_type d) const
00399 {
00400     return const_iterator(&m_field[-d]);
00401 }
00402 
00403 inline record::difference_type record::const_iterator::operator -(record::const_iterator const &rhs) const
00404 {
00405     return &rhs.m_field[0] - &m_field[0];
00406 }
00407 
00408 inline bool record::const_iterator::is_equal(record::const_iterator const &rhs) const
00409 {
00410     return rhs.m_field == m_field;
00411 }
00412 
00413 #if defined(__BORLANDC__) || \
00414     defined(__DMC__)
00415 inline bool record::const_iterator::operator ==(record::const_iterator const &rhs) const
00416 {
00417     return is_equal(rhs);
00418 }
00419 
00420 inline bool record::const_iterator::operator !=(record::const_iterator const &rhs) const
00421 {
00422     return !is_equal(rhs);
00423 }
00424 #endif /* compiler */
00425 
00426 // record::same_name
00427 
00428 struct record::same_name
00429 {
00430 public:
00431     same_name()
00432         : m_name()
00433     {}
00434     same_name(string_t const &name)
00435         : m_name(name)
00436     {}
00437 
00438 public:
00439     bool operator ()(string_t const &lhs, string_t const &rhs) const
00440     {
00441         return lhs < rhs;
00442     }
00443     bool operator ()(ORJFieldA const &lhs, ORJFieldA const &rhs) const
00444     {
00445         return operator ()(string_t(lhs.name.ptr, lhs.name.len), string_t(rhs.name.ptr, rhs.name.len));
00446     }
00447     bool operator ()(string_t const &lhs, ORJFieldA const &rhs) const
00448     {
00449         return operator ()(lhs, string_t(rhs.name.ptr, rhs.name.len));
00450     }
00451     bool operator ()(ORJFieldA const &lhs, string_t const &rhs) const
00452     {
00453         return operator ()(string_t(lhs.name.ptr, lhs.name.len), rhs);
00454     }
00455     bool operator ()(ORJFieldA const &f) const
00456     {
00457         return m_name == f.name.ptr;
00458     }
00459     bool operator ()(field const &f) const
00460     {
00461         return m_name == f.name();
00462     }
00463 
00464 private:
00465     string_t const  m_name;
00466 
00467 private:
00468     same_name &operator =(same_name const &);
00469 };
00470 
00471 // record
00472 
00473 inline ORJField const *record::find_field_(string_t const &name) const
00474 {
00475     // We do a boring linear search.
00476     ORJField const  *const  b           =   &m_record->fields[0];
00477     ORJField const  *const  e           =   &m_record->fields[m_record->numFields];
00478     ORJField const          *it;
00479     ORJDatabase const       *database   =   ORJ_Record_GetDatabaseA(m_record);
00480 
00481     if(ORJ_FLAG_ORDERFIELDS == (database->flags & ORJ_FLAG_ORDERFIELDS))
00482     {
00483         // Ordered, so we can do a binary search
00484         it  =   std::lower_bound(b, e, name, same_name());
00485 
00486         if(e != it)
00487         {
00488 #if defined(STLSOFT_COMPILER_IS_GCC) && \
00489     __GNUC__ < 3
00490             // This copes with the non-standard GCC 2.x standard library, but
00491             // will also work with a good one (albeit less efficiently).
00492             if(0 == string_t((*it).name.ptr, (*it).name.len).compare(name))
00493 #else /* ? compiler */
00494             if(0 != name.compare(0, (*it).name.len, (*it).name.ptr))
00495 #endif /* compiler */
00496             {
00497                 it = e;
00498             }
00499         }
00500     }
00501     else
00502     {
00503         // Unordered, so we must do a linear search
00504         it  =   std::find_if(b, e, same_name(name));
00505     }
00506 
00507     if(e == it)
00508     {
00509         it = NULL;
00510     }
00511 
00512     return it;
00513 }
00514 
00515 inline size_t record::count_fields_(string_t const &name) const
00516 {
00517     ORJField const  *const  b           =   &m_record->fields[0];
00518     ORJField const  *const  e           =   &m_record->fields[m_record->numFields];
00519     ORJDatabase const       *database   =   ORJ_Record_GetDatabaseA(m_record);
00520 
00521     if(ORJ_FLAG_ORDERFIELDS == (database->flags & ORJ_FLAG_ORDERFIELDS))
00522     {
00523         // Ordered, so we can do a binary search
00524         ORJField const  *lower  =   std::lower_bound(b, e, name, same_name());
00525         ORJField const  *upper  =   std::upper_bound(b, e, name, same_name());
00526 
00527         return static_cast<size_t>(std::distance(lower, upper)); // distance() return ptrdiff_t
00528     }
00529     else
00530     {
00531         // Unordered, so we must do a linear search
00532         return static_cast<size_t>(std::count_if(b, e, same_name(name))); // some impls do not return size_t
00533     }
00534 }
00535 
00536 inline record::record(ORJRecord const *record)
00537     : m_record(record)
00538 {}
00539 
00540 inline record::record()
00541     : m_record(NULL)
00542 {}
00543 
00544 inline record::record(record const &rhs)
00545     : m_record(rhs.m_record)
00546 {}
00547 
00548 inline record &record::operator =(record const &rhs)
00549 {
00550     m_record = rhs.m_record;
00551 
00552     return *this;
00553 }
00554 
00555 inline size_t record::size() const
00556 {
00557     openrj_assert(NULL != m_record);
00558 
00559     return ORJ_Record_GetNumFieldsA(m_record);
00560 }
00561 
00562 inline string_t record::comment() const
00563 {
00564     openrj_assert(NULL != m_record);
00565 
00566     return string_t(m_record->comment.ptr, m_record->comment.len);
00567 }
00568 
00569 inline bool record::empty() const
00570 {
00571     return 0 == size();
00572 }
00573 
00574 inline const field record::operator [](size_t index) const
00575 {
00576     openrj_assert(index <= size());
00577 
00578     return field(&m_record->fields[index]);
00579 }
00580 
00581 inline bool record::has_field(string_t const &name) const
00582 {
00583     return NULL != find_field_(name);
00584 }
00585 
00586 #if 0
00587 inline bool record::has_field(string_t const &name, string_t const &value) const
00588 {
00589     return NULL != find_field_(name, value);
00590 }
00591 #endif /* 0 */
00592 
00593 inline size_t record::count_fields(string_t const &name) const
00594 {
00595     return count_fields_(name);
00596 }
00597 
00598 #if defined(STLSOFT_COMPILER_IS_MSVC) && \
00599     _MSC_VER >= 1200
00600 # pragma warning(push)
00601 # pragma warning(disable : 4702)
00602 #endif /* compiler */
00603 
00604 inline const string_t record::operator [](string_t const &name) const // throw (std::out_of_range)
00605 {
00606     ORJField const  *r  =   find_field_(name);
00607 
00608     if(NULL == r)
00609     {
00610         throw std::out_of_range(stlsoft::c_str_ptr("record does not contain field named \"" + name + "\""));
00611     }
00612 
00613     return field(&*r).value();
00614 }
00615 
00616 #if defined(STLSOFT_COMPILER_IS_MSVC) && \
00617     _MSC_VER >= 1200
00618 # pragma warning(pop)
00619 #endif /* compiler */
00620 
00621 inline string_t record::get_field_value(string_t const &name, string_t const &defValue) const
00622 {
00623     ORJField const  *r  =   find_field_(name);
00624 
00625     return (NULL == r) ? defValue : field(&*r).value();
00626 }
00627 
00628 inline record::const_iterator record::begin() const
00629 {
00630     openrj_assert(NULL != m_record);
00631 
00632     return &m_record->fields[0];
00633 }
00634 
00635 inline record::const_iterator record::end() const
00636 {
00637     openrj_assert(NULL != m_record);
00638 
00639     return &m_record->fields[m_record->numFields];
00640 }
00641 
00642 #if defined(__STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT)
00643 inline record::const_reverse_iterator record::rbegin() const
00644 {
00645     return const_reverse_iterator(end());
00646 }
00647 
00648 inline record::const_reverse_iterator record::rend() const
00649 {
00650     return const_reverse_iterator(begin());
00651 }
00652 #endif /* __STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT */
00653 
00654 /* /////////////////////////////////////////////////////////////////////////////
00655  * Namespace
00656  */
00657 
00658 } // namespace stl
00659 } // namespace openrj
00660 
00661 /* ////////////////////////////////////////////////////////////////////////// */
00662 
00663 #endif /* !OPENRJ_INCL_OPENRJ_STL_HPP_RECORD */
00664 
00665 /* ////////////////////////////////////////////////////////////////////////// */

Open-RJ Library documentation © Synesis Software Pty Ltd, 2004-2005