• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Errata.cc

Go to the documentation of this file.
00001 /** @file
00002     Errata implementation.
00003 
00004     @section license License
00005 
00006     Licensed to the Apache Software Foundation (ASF) under one
00007     or more contributor license agreements.  See the NOTICE file
00008     distributed with this work for additional information
00009     regarding copyright ownership.  The ASF licenses this file
00010     to you under the Apache License, Version 2.0 (the
00011     "License"); you may not use this file except in compliance
00012     with the License.  You may obtain a copy of the License at
00013 
00014     http://www.apache.org/licenses/LICENSE-2.0
00015 
00016     Unless required by applicable law or agreed to in writing, software
00017     distributed under the License is distributed on an "AS IS" BASIS,
00018     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019     See the License for the specific language governing permissions and
00020     limitations under the License.
00021  */
00022 
00023 # include "Errata.h"
00024 # include <iostream>
00025 # include <sstream>
00026 # include <iomanip>
00027 # include <algorithm>
00028 # include <memory.h>
00029 
00030 namespace ts {
00031 
00032 /** List of sinks for abandoned erratum.
00033  */
00034 namespace {
00035   std::deque<Errata::Sink::Handle> Sink_List;
00036 }
00037 
00038 std::string const Errata::DEFAULT_GLUE("\n");
00039 Errata::Message const Errata::NIL_MESSAGE;
00040 Errata::Code Errata::Message::Default_Code = 0;
00041 Errata::Message::SuccessTest const Errata::Message::DEFAULT_SUCCESS_TEST =
00042   &Errata::Message::isCodeZero;
00043 Errata::Message::SuccessTest Errata::Message::Success_Test =
00044   Errata::Message::DEFAULT_SUCCESS_TEST;
00045 
00046 bool
00047 Errata::Message::isCodeZero(Message const& msg) {
00048   return msg.m_code == 0;
00049 }
00050 
00051 void
00052 Errata::Data::push(Message const& msg) {
00053   m_items.push_back(msg);
00054 }
00055 
00056 Errata::Message const&
00057 Errata::Data::top() const {
00058   return m_items.size() ? m_items.back() : NIL_MESSAGE ;
00059 }
00060 
00061 inline Errata::Errata(ImpPtr const& ptr) 
00062   : m_data(ptr) {
00063 }
00064 
00065 Errata::Data::~Data() {
00066   if (m_log_on_delete) {
00067     Errata tmp(this); // because client API requires a wrapper.
00068     std::deque<Errata::Sink::Handle>::iterator spot, limit;
00069     for ( spot = Sink_List.begin(), limit = Sink_List.end();
00070           spot != limit;
00071           ++spot
00072     ) {
00073       (**spot)(tmp);
00074     }
00075     tmp.m_data.release(); // don't delete this again.
00076   }
00077 }
00078 
00079 Errata::Errata() {
00080 }
00081 
00082 Errata::Errata(self const& that)
00083   : m_data(that.m_data) {
00084 }
00085 
00086 Errata::Errata(std::string const& text) {
00087   this->push(text);
00088 }
00089 
00090 Errata::Errata(Id id, std::string const& text) {
00091   this->push(id, text);
00092 }
00093 
00094 Errata::~Errata() {
00095 }
00096 
00097 /*  This forces the errata to have a data object that only it references.
00098     If we're sharing the data, clone. If there's no data, allocate.
00099     This is used just before a write operation to have copy on write semantics.
00100  */
00101 Errata::Data*
00102 Errata::pre_write() {
00103   if (m_data) {
00104     if (m_data.useCount() > 1) {
00105       m_data = new Data(*m_data); // clone current data
00106     }
00107   } else { // create new data
00108     m_data = new Data;
00109   }
00110   return m_data.get();
00111 }
00112 
00113 // Just create an instance if needed.
00114 Errata::Data*
00115 Errata::instance() {
00116   if (!m_data) m_data = new Data;
00117   return m_data.get();
00118 }
00119 
00120 Errata&
00121 Errata::push(Message const& msg) {
00122   this->pre_write()->push(msg);
00123   return *this;
00124 }
00125 
00126 Errata&
00127 Errata::operator=(self const& that) {
00128   m_data = that.m_data;
00129   return *this;
00130 }
00131 
00132 Errata&
00133 Errata::operator = (Message const& msg) {
00134   // Avoid copy on write in the case where we discard.
00135   if (!m_data || m_data.useCount() > 1) {
00136     this->clear();
00137     this->push(msg);
00138   } else {
00139     m_data->m_items.clear();
00140     m_data->push(msg);
00141   }
00142   return *this;
00143 }
00144 
00145 Errata&
00146 Errata::pull(self& that) {
00147   if (that.m_data) {
00148     this->pre_write();
00149     m_data->m_items.insert(
00150       m_data->m_items.end(),
00151       that.m_data->m_items.begin(),
00152       that.m_data->m_items.end()
00153     );
00154     that.m_data->m_items.clear();
00155   }
00156   return *this;
00157 }
00158 
00159 void
00160 Errata::pop() {
00161   if (m_data && m_data->size()) {
00162     this->pre_write()->m_items.pop_front();
00163   }
00164   return;
00165 }
00166 
00167 void
00168 Errata::clear() {
00169   m_data.reset(0);
00170 }
00171 
00172 /*  We want to allow iteration on empty / nil containers because that's very
00173     convenient for clients. We need only return the same value for begin()
00174     and end() and everything works as expected.
00175 
00176     However we need to be a bit more clever for VC 8.  It checks for
00177     iterator compatibility, i.e. that the iterators are not
00178     invalidated and that they are for the same container.  It appears
00179     that default iterators are not compatible with anything.  So we
00180     use static container for the nil data case.
00181  */
00182 static Errata::Container NIL_CONTAINER;
00183 
00184 Errata::iterator
00185 Errata::begin() {
00186   return m_data ? m_data->m_items.rbegin() : NIL_CONTAINER.rbegin();
00187 }
00188 
00189 Errata::const_iterator
00190 Errata::begin() const {
00191   return m_data ? static_cast<Data const&>(*m_data).m_items.rbegin()
00192     : static_cast<Container const&>(NIL_CONTAINER).rbegin();
00193 }
00194 
00195 Errata::iterator
00196 Errata::end() {
00197   return m_data ? m_data->m_items.rend() : NIL_CONTAINER.rend();
00198 }
00199 
00200 Errata::const_iterator
00201 Errata::end() const {
00202   return m_data ? static_cast<Data const&>(*m_data).m_items.rend()
00203     : static_cast<Container const&>(NIL_CONTAINER).rend();
00204 }
00205 
00206 void
00207 Errata::registerSink(Sink::Handle const& s) {
00208   Sink_List.push_back(s);
00209 }
00210 
00211 std::ostream&
00212 Errata::write(
00213   std::ostream& out,
00214   int offset,
00215   int indent,
00216   int shift,
00217   char const* lead
00218 ) const {
00219   for ( const_iterator spot = this->begin(), limit = this->end();
00220         spot != limit;
00221         ++spot
00222   ) {
00223     if ((offset + indent) > 0)
00224       out << std::setw(indent + offset) << std::setfill(' ')
00225           << ((indent > 0 && lead) ? lead : " ");
00226 
00227     out << spot->m_id << " [" << spot->m_code << "]: " << spot->m_text
00228         << std::endl
00229       ;
00230     if (spot->getErrata().size())
00231       spot->getErrata().write(out, offset, indent+shift, shift, lead);
00232 
00233   }
00234   return out;
00235 }
00236 
00237 size_t
00238 Errata::write(
00239   char *buff,
00240   size_t n,
00241   int offset,
00242   int indent,
00243   int shift,
00244   char const* lead
00245 ) const {
00246   std::ostringstream out;
00247   std::string text;
00248   this->write(out, offset, indent, shift, lead);
00249   text = out.str();
00250   memcpy(buff, text.data(), std::min(n, text.size()));
00251   return text.size();
00252 }
00253 
00254 std::ostream& operator<< (std::ostream& os, Errata const& err) {
00255   return err.write(os, 0, 0, 2, "> ");
00256 }
00257 
00258 # if USING_BOOST
00259 
00260 std::ostream&
00261 errata::format(std::ostream& s, std::string const& fmt, std::string const& glue) const {
00262   return this->format(s, boost::format(fmt), glue);
00263 }
00264 
00265 std::ostream&
00266 errata::format(std::ostream& s, boost::format const& fmt, std::string const& glue) const {
00267   if (_data) {
00268     bool inside = false;
00269     boost::format f(fmt);
00270     f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
00271     const_iterator spot(this->begin()), limit(this->end());
00272     while (spot != limit) {
00273       if (inside) s << glue;
00274       s << ( f % spot->_id % spot->_text );
00275       inside = true;
00276       ++spot;
00277     }
00278   }
00279   return s;
00280 }
00281 
00282 std::string
00283 errata::format(std::string const& fmt, std::string const& glue) const {
00284   return this->format(boost::format(fmt), glue);
00285 }
00286 
00287 std::string
00288 errata::format(boost::format const& fmt, std::string const& glue) const {
00289   std::ostringstream s;
00290   this->format(s, fmt, glue);
00291   return s.str();
00292 }
00293 
00294 # endif
00295 
00296 } // namespace ts
00297 

Generated by  doxygen 1.7.1