TupleAccessor.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/tuple/TupleAccessor.cpp#18 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2005-2009 SQLstream, Inc.
00006 // Copyright (C) 2005-2009 LucidEra, Inc.
00007 // Portions Copyright (C) 1999-2009 John V. Sichi
00008 //
00009 // This program is free software; you can redistribute it and/or modify it
00010 // under the terms of the GNU General Public License as published by the Free
00011 // Software Foundation; either version 2 of the License, or (at your option)
00012 // any later version approved by The Eigenbase Project.
00013 //
00014 // This program is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU General Public License
00020 // along with this program; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 */
00023 
00024 #include "fennel/common/CommonPreamble.h"
00025 #include "fennel/tuple/TupleAccessor.h"
00026 #include "fennel/tuple/TupleDescriptor.h"
00027 #include "fennel/tuple/TupleData.h"
00028 #include "fennel/tuple/AttributeAccessorImpl.h"
00029 #include "fennel/tuple/StoredTypeDescriptor.h"
00030 #include <boost/lambda/bind.hpp>
00031 #include <boost/lambda/construct.hpp>
00032 
00033 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/tuple/TupleAccessor.cpp#18 $");
00034 
00035 const bool TupleAccessor::BOOL_TRUE = true;
00036 
00037 const bool TupleAccessor::BOOL_FALSE = false;
00038 
00039 // NOTE jvs 11-Feb-2006: Set this to 1 to debug problems with
00040 // TupleAccessor::setCurrentTupleBuf being passed invalid tuple images.
00041 // Typical symptom is a Boost assertion failure in ~TupleAccessor when
00042 // dynamic_bitset detects invalid bits set.  When this is set to 1, we write a
00043 // magic number as a prefix every time a tuple is marshalled, and verify it
00044 // when setCurrentTupleBuf is called.  CAUTION: do NOT check in changes with
00045 // this set to 1!  Also realize that this affects on-disk storage, so if you
00046 // run without it and generate a datafile, then run with it and read that
00047 // datafile, you should expect an assertion failure.
00048 #define DEBUG_TUPLE_ACCESS 0
00049 
00053 static const MagicNumber TUPLE_MAGIC_NUMBER = 0x9897ab509de7dcf5LL;
00054 
00055 TupleAccessor::TupleAccessor()
00056 {
00057     pTupleBuf = NULL;
00058 }
00059 
00060 TupleAccessor::~TupleAccessor()
00061 {
00062     clear();
00063 }
00064 
00065 void TupleAccessor::clear()
00066 {
00067     using namespace boost::lambda;
00068     std::for_each(
00069         ppAttributeAccessors.begin(),
00070         ppAttributeAccessors.end(),
00071         bind(delete_ptr(),_1));
00072     ppAttributeAccessors.clear();
00073     pVarWidthAttrIndices.clear();
00074     marshalOrder.clear();
00075     pTupleBuf = NULL;
00076     bAlignedVar = false;
00077 }
00078 
00079 // TODO:  clean up template factory craziness below, and add network support
00080 // for 64-bit types and UNICODE
00081 
00082 // NOTE:  there's a small amount of code in Farrago which is sensitive to this
00083 // algorithm, e.g. bit field ordering
00084 
00085 void TupleAccessor::compute(
00086     TupleDescriptor const &tuple,TupleFormat formatInit)
00087 {
00088     clear();
00089     format = formatInit;
00090 
00091     // these vectors keep track of the logical 0-based indices of the
00092     // attributes belonging to the various attribute storage classes
00093     VectorOfUint aligned8;
00094     VectorOfUint aligned4;
00095     VectorOfUint aligned2;
00096     VectorOfUint unalignedFixed;
00097     VectorOfUint unalignedVar;
00098     VectorOfUint alignedVar2;
00099 
00100     // special-case reference to the accessor for the first variable-width
00101     // attribute
00102     AttributeAccessor *pFirstVariableAccessor = NULL;
00103 
00104     // number of bit fields seen so far
00105     nBitFields = 0;
00106 
00107     // sum of max storage size for variable-width attributes seen so far
00108     uint cbVarDataMax = 0;
00109 
00110     // sum of total storage size seen so far; this is used as an accumulator
00111     // for assigning actual offsets
00112     cbMaxStorage = 0;
00113 
00114 #if DEBUG_TUPLE_ACCESS
00115     cbMaxStorage += sizeof(MagicNumber);
00116 #endif
00117 
00118     // first pass over all attributes in logical order:  collate them into
00119     // storage classes and precompute everything we can
00120     for (uint iAttr = 0; iAttr < tuple.size(); iAttr++) {
00121         AttributeAccessor *pNewAccessor;
00122         TupleAttributeDescriptor const &attr = tuple[iAttr];
00123         uint cbFixed = attr.pTypeDescriptor->getFixedByteCount();
00124         uint cbMin = attr.pTypeDescriptor->getMinByteCount(attr.cbStorage);
00125         if (cbFixed) {
00126             assert(cbFixed == attr.cbStorage);
00127             assert(cbFixed == cbMin);
00128         }
00129         bool bFixedWidth = (cbMin == attr.cbStorage);
00130         if (bFixedWidth && !attr.cbStorage) {
00131             if (!attr.pTypeDescriptor->getMinByteCount(1)) {
00132                 // this is a "0-length variable-width" field masquerading
00133                 // as a fixed-width field
00134                 bFixedWidth = false;
00135             }
00136         }
00137         bool bNullable = attr.isNullable;
00138         uint nBits = (attr.pTypeDescriptor->getBitCount());
00139         assert(nBits <= 1);
00140         if (format == TUPLE_FORMAT_ALL_FIXED) {
00141             bFixedWidth = true;
00142             nBits = 0;
00143         }
00144         uint iAlign = attr.pTypeDescriptor->getAlignmentByteCount(
00145             attr.cbStorage);
00146         if (!bFixedWidth) {
00147             cbVarDataMax += attr.cbStorage;
00148             if (iAlign == 2) {
00149                 alignedVar2.push_back(iAttr);
00150                 bAlignedVar = true;
00151             } else {
00152                 assert(iAlign == 1);
00153                 unalignedVar.push_back(iAttr);
00154             }
00155             // We need to defer actual creation of the accessor until
00156             // after we've sorted out aligned from unaligned, so just
00157             // fill a placeholder into the array for now and
00158             // we'll overwrite it later.
00159             pNewAccessor = new VarOffsetAccessor<false>();
00160         } else if (nBits) {
00161             if (bNullable) {
00162                 pNewAccessor = new NullableAccessor<BitAccessor>;
00163             } else {
00164                 pNewAccessor = new BitAccessor;
00165             }
00166             pNewAccessor->iValueBit = nBitFields;
00167             nBitFields++;
00168         } else {
00169             assert((cbMin % iAlign) == 0);
00170             bool bArray =
00171                 StandardTypeDescriptor::isArray(
00172                     StandardTypeDescriptorOrdinal(
00173                         attr.pTypeDescriptor->getOrdinal()));
00174             switch (iAlign) {
00175             case 2:
00176                 if (bNullable) {
00177                     if ((format == TUPLE_FORMAT_NETWORK) && !bArray) {
00178                         pNewAccessor =
00179                             new NullableAccessor<FixedWidthNetworkAccessor16>;
00180                     } else {
00181                         pNewAccessor =
00182                             new NullableAccessor<FixedWidthAccessor>;
00183                     }
00184                 } else {
00185                     if ((format == TUPLE_FORMAT_NETWORK) && !bArray) {
00186                         pNewAccessor = new FixedWidthNetworkAccessor16;
00187                     } else {
00188                         pNewAccessor = new FixedWidthAccessor;
00189                     }
00190                 }
00191                 break;
00192             case 4:
00193                 if (bNullable) {
00194                     if (format == TUPLE_FORMAT_NETWORK) {
00195                         pNewAccessor =
00196                             new NullableAccessor<FixedWidthNetworkAccessor32>;
00197                     } else {
00198                         pNewAccessor =
00199                             new NullableAccessor<FixedWidthAccessor>;
00200                     }
00201                 } else {
00202                     if (format == TUPLE_FORMAT_NETWORK) {
00203                         pNewAccessor = new FixedWidthNetworkAccessor32;
00204                     } else {
00205                         pNewAccessor = new FixedWidthAccessor;
00206                     }
00207                 }
00208                 break;
00209             case 8:
00210                 if (bNullable) {
00211                     if (format == TUPLE_FORMAT_NETWORK) {
00212                         pNewAccessor =
00213                             new NullableAccessor<FixedWidthNetworkAccessor64>;
00214                     } else {
00215                         pNewAccessor =
00216                             new NullableAccessor<FixedWidthAccessor>;
00217                     }
00218                 } else {
00219                     if (format == TUPLE_FORMAT_NETWORK) {
00220                         pNewAccessor = new FixedWidthNetworkAccessor64;
00221                     } else {
00222                         pNewAccessor = new FixedWidthAccessor;
00223                     }
00224                 }
00225                 break;
00226             default:
00227                 if (bNullable) {
00228                     pNewAccessor = new NullableAccessor<FixedWidthAccessor>;
00229                 } else {
00230                     pNewAccessor = new FixedWidthAccessor;
00231                 }
00232                 break;
00233             }
00234             switch (iAlign) {
00235             case 1:
00236                 unalignedFixed.push_back(iAttr);
00237                 break;
00238             case 2:
00239                 aligned2.push_back(iAttr);
00240                 break;
00241             case 4:
00242                 aligned4.push_back(iAttr);
00243                 break;
00244             case 8:
00245                 aligned8.push_back(iAttr);
00246                 break;
00247             default:
00248                 permAssert(false);
00249             }
00250         }
00251         if (bNullable) {
00252             pNewAccessor->iNullBit = nBitFields;
00253             nBitFields++;
00254         }
00255         pNewAccessor->cbStorage = attr.cbStorage;
00256         ppAttributeAccessors.push_back(pNewAccessor);
00257     }
00258     bitFields.resize(nBitFields);
00259 
00260     // fill in variable-width attributes, since we had to defer them
00261     // above so that we could collect aligned ones before unaligned ones
00262     pVarWidthAttrIndices.resize(alignedVar2.size() + unalignedVar.size());
00263     std::copy(
00264         alignedVar2.begin(), alignedVar2.end(),
00265         pVarWidthAttrIndices.begin());
00266     std::copy(
00267         unalignedVar.begin(), unalignedVar.end(),
00268         pVarWidthAttrIndices.begin() + alignedVar2.size());
00269     for (uint i = 0; i < pVarWidthAttrIndices.size(); ++i) {
00270         uint iAttr = pVarWidthAttrIndices[i];
00271         TupleAttributeDescriptor const &attr = tuple[iAttr];
00272         bool bNullable = attr.isNullable;
00273         AttributeAccessor *pNewAccessor;
00274         if (pFirstVariableAccessor) {
00275             if (bNullable) {
00276                 if (format == TUPLE_FORMAT_NETWORK) {
00277                     pNewAccessor =
00278                         new NullableAccessor< VarOffsetAccessor<true> >;
00279                 } else {
00280                     pNewAccessor =
00281                         new NullableAccessor< VarOffsetAccessor<false> >;
00282                 }
00283             } else {
00284                 if (format == TUPLE_FORMAT_NETWORK) {
00285                     pNewAccessor = new VarOffsetAccessor<true>;
00286                 } else {
00287                     pNewAccessor = new VarOffsetAccessor<false>;
00288                 }
00289             }
00290         } else {
00291             if (bNullable) {
00292                 if (format == TUPLE_FORMAT_NETWORK) {
00293                     pFirstVariableAccessor =
00294                         new NullableAccessor<
00295                         FixedOffsetVarWidthAccessor<true> >;
00296                 } else {
00297                     pFirstVariableAccessor =
00298                         new NullableAccessor<
00299                         FixedOffsetVarWidthAccessor<false> >;
00300                 }
00301             } else {
00302                 if (format == TUPLE_FORMAT_NETWORK) {
00303                     pFirstVariableAccessor =
00304                         new FixedOffsetVarWidthAccessor<true>;
00305                 } else {
00306                     pFirstVariableAccessor =
00307                         new FixedOffsetVarWidthAccessor<false>;
00308                 }
00309             }
00310             pNewAccessor = pFirstVariableAccessor;
00311         }
00312         AttributeAccessor *pPlaceholder = ppAttributeAccessors[iAttr];
00313         pNewAccessor->cbStorage = attr.cbStorage;
00314         pNewAccessor->iNullBit = pPlaceholder->iNullBit;
00315         // overwrite placeholder
00316         ppAttributeAccessors[iAttr] = pNewAccessor;
00317         delete pPlaceholder;
00318     }
00319 
00320     // now, make a pass over each storage class, calculating actual offsets;
00321     // note that initFixedAccessors advances cbMaxStorage as a side-effect
00322     initFixedAccessors(tuple,aligned8);
00323     initFixedAccessors(tuple,aligned4);
00324     initFixedAccessors(tuple,aligned2);
00325 
00326     if (pFirstVariableAccessor) {
00327         iFirstVarEndIndirectOffset = cbMaxStorage;
00328     } else {
00329         iFirstVarEndIndirectOffset = MAXU;
00330     }
00331 
00332     for (uint i = 0; i < pVarWidthAttrIndices.size(); i++) {
00333         ppAttributeAccessors[pVarWidthAttrIndices[i]]->iEndIndirectOffset =
00334             cbMaxStorage;
00335         cbMaxStorage += sizeof(StoredValueOffset);
00336     }
00337 
00338     if (pFirstVariableAccessor) {
00339         iLastVarEndIndirectOffset = cbMaxStorage - sizeof(StoredValueOffset);
00340     } else {
00341         iLastVarEndIndirectOffset = MAXU;
00342     }
00343 
00344     initFixedAccessors(tuple,unalignedFixed);
00345 
00346     if (nBitFields) {
00347         iBitFieldOffset = cbMaxStorage;
00348     } else {
00349         iBitFieldOffset = MAXU;
00350     }
00351     cbMaxStorage += bytesForBits(nBitFields);
00352     if (pFirstVariableAccessor) {
00353         if (bAlignedVar) {
00354             // First variable-width value needs to be 2-byte aligned,
00355             // so add one byte of padding if necessary.
00356             if (cbMaxStorage & 1) {
00357                 ++cbMaxStorage;
00358             }
00359         }
00360         pFirstVariableAccessor->iFixedOffset = cbMaxStorage;
00361         iFirstVarOffset = cbMaxStorage;
00362     } else {
00363         iFirstVarOffset = MAXU;
00364     }
00365     cbMinStorage = cbMaxStorage;
00366     cbMaxStorage += cbVarDataMax;
00367 
00368     // Avoid 0-byte tuples, because it's very hard to count something
00369     // that isn't there.  This bumps them up to 1-byte, which will get
00370     // further bumped up to the minimum alignment unit below.
00371     if (!cbMaxStorage) {
00372         cbMinStorage = 1;
00373         cbMaxStorage = 1;
00374     }
00375 
00376     // now round the entire row width up to the next alignment boundary;
00377     // this only affects the end of the row, which is why it is done
00378     // AFTER computing cbMaxStorage based on the unaligned cbMinStorage
00379     cbMinStorage = alignRoundUp(cbMinStorage);
00380     cbMaxStorage = alignRoundUp(cbMaxStorage);
00381 
00382     // if aligned variable-width fields are present, permute the marshalling
00383     // order so that they come before unaligned variable-width fields
00384     if (bAlignedVar) {
00385         // add all of the fixed-width attributes
00386         for (uint i = 0; i < tuple.size(); ++i) {
00387             AttributeAccessor const &accessor = getAttributeAccessor(i);
00388             if (isMAXU(accessor.iEndIndirectOffset)) {
00389                 marshalOrder.push_back(i);
00390             }
00391         }
00392         uint nFixed = marshalOrder.size();
00393         assert(nFixed + pVarWidthAttrIndices.size() == tuple.size());
00394         marshalOrder.resize(tuple.size());
00395         // then all of the variable-width attributes, in the correct order
00396         std::copy(
00397             pVarWidthAttrIndices.begin(),
00398             pVarWidthAttrIndices.end(),
00399             marshalOrder.begin() + nFixed);
00400     }
00401 }
00402 
00403 void TupleAccessor::initFixedAccessors(
00404     TupleDescriptor const &tuple,VectorOfUint &v)
00405 {
00406     for (uint i = 0; i < v.size(); i++) {
00407         uint iAttr = v[i];
00408         TupleAttributeDescriptor const &attr = tuple[iAttr];
00409         AttributeAccessor &accessor = *(ppAttributeAccessors[iAttr]);
00410         accessor.iFixedOffset = cbMaxStorage;
00411         cbMaxStorage += attr.cbStorage;
00412     }
00413 }
00414 
00415 uint TupleAccessor::getBufferByteCount(PConstBuffer pBuf) const
00416 {
00417     if (isFixedWidth()) {
00418         return cbMaxStorage;
00419     } else {
00420         // variable-width tuple:  use the end of the last variable-width
00421         // attribute
00422         StoredValueOffset cb =
00423             *referenceIndirectOffset(
00424                 const_cast<PBuffer>(pBuf),
00425                 iLastVarEndIndirectOffset);
00426         if (format == TUPLE_FORMAT_NETWORK) {
00427             cb = ntohs(cb);
00428         }
00429         // round up for alignment padding
00430         return alignRoundUp(cb);
00431     }
00432 }
00433 
00434 uint TupleAccessor::getByteCount(TupleData const &tuple) const
00435 {
00436     if (isFixedWidth()) {
00437         return cbMaxStorage;
00438     } else {
00439         // variable-width tuple:  add up all var-width fields
00440         uint cb = iFirstVarOffset;
00441         for (uint i = 0; i < pVarWidthAttrIndices.size(); ++i) {
00442             TupleDatum const &datum = tuple[pVarWidthAttrIndices[i]];
00443             if (datum.pData) {
00444                 cb += datum.cbData;
00445             }
00446         }
00447         // round up for alignment padding
00448         return alignRoundUp(cb);
00449     }
00450 }
00451 
00452 bool TupleAccessor::isBufferSufficient(
00453     TupleData const &tuple,uint cbBuffer) const
00454 {
00455     // fast optimistic check
00456     if (getMaxByteCount() <= cbBuffer) {
00457         return true;
00458     }
00459     // slower conservative check
00460     return getByteCount(tuple) <= cbBuffer;
00461 }
00462 
00463 void TupleAccessor::setCurrentTupleBuf(PConstBuffer pTupleBufInit, bool valid)
00464 {
00465     assert(pTupleBufInit);
00466     pTupleBuf = pTupleBufInit;          // bind to buffer
00467     if (!isMAXU(iBitFieldOffset)) {
00468         // if buffer holds a valid marshalled tuple, load its bitFields
00469         if (valid) {
00470 #if DEBUG_TUPLE_ACCESS
00471             assert(
00472                 *reinterpret_cast<MagicNumber const *>(pTupleBuf)
00473                 == TUPLE_MAGIC_NUMBER);
00474 #endif
00475             // TODO:  trick dynamic_bitset to avoid copy
00476             boost::from_block_range(
00477                 pTupleBuf + iBitFieldOffset,
00478                 pTupleBuf + iBitFieldOffset + bitFields.num_blocks(),
00479                 bitFields);
00480         }
00481     }
00482 }
00483 
00484 void TupleAccessor::resetCurrentTupleBuf()
00485 {
00486     pTupleBuf = NULL;
00487 }
00488 
00489 void TupleAccessor::unmarshal(TupleData &tuple,uint iFirstDatum) const
00490 {
00491     uint n = std::min(tuple.size() - iFirstDatum,ppAttributeAccessors.size());
00492 
00493     if ((format == TUPLE_FORMAT_NETWORK) || bAlignedVar) {
00494         // for TUPLE_FORMAT_NETWORK, unmarshal attributes individually
00495         for (uint i = 0; i < n; ++i) {
00496             getAttributeAccessor(i).unmarshalValue(
00497                 *this,tuple[iFirstDatum + i]);
00498         }
00499         return;
00500     }
00501 
00502     // for other formats, we can go a little faster by avoiding per-attribute
00503     // call overhead
00504 
00505     uint iNextVarOffset = iFirstVarOffset;
00506     StoredValueOffset const *pNextVarEndOffset =
00507         referenceIndirectOffset(iFirstVarEndIndirectOffset);
00508 
00509     for (uint i = 0; i < n; i++) {
00510         TupleDatum &value = tuple[i + iFirstDatum];
00511         AttributeAccessor const &accessor = getAttributeAccessor(i);
00512         if (!isMAXU(accessor.iNullBit)) {
00513             if (bitFields[accessor.iNullBit]) {
00514                 value.pData = NULL;
00515                 if (!isMAXU(accessor.iEndIndirectOffset)) {
00516                     pNextVarEndOffset++;
00517                 }
00518                 continue;
00519             }
00520         }
00521         if (!isMAXU(accessor.iFixedOffset)) {
00522             value.pData = getCurrentTupleBuf() + accessor.iFixedOffset;
00523         } else if (isMAXU(accessor.iValueBit)) {
00524             value.pData = getCurrentTupleBuf() + iNextVarOffset;
00525         } else {
00526             static_cast<BitAccessor const &>(accessor).unmarshalValue(
00527                 *this,value);
00528         }
00529         if (!isMAXU(accessor.iEndIndirectOffset)) {
00530             assert(pNextVarEndOffset ==
00531                    referenceIndirectOffset(accessor.iEndIndirectOffset));
00532             uint iEndOffset = *pNextVarEndOffset;
00533             pNextVarEndOffset++;
00534             value.cbData = iEndOffset - iNextVarOffset;
00535             iNextVarOffset = iEndOffset;
00536         }
00537         assert(value.cbData <= accessor.cbStorage);
00538     }
00539 }
00540 
00541 void TupleAccessor::marshal(TupleData const &tuple,PBuffer pTupleBufDest)
00542 {
00543 #if DEBUG_TUPLE_ACCESS
00544     *reinterpret_cast<MagicNumber *>(pTupleBufDest) = TUPLE_MAGIC_NUMBER;
00545 #endif
00546 
00547     pTupleBuf = pTupleBufDest;
00548 
00549     uint iNextVarOffset = iFirstVarOffset;
00550     StoredValueOffset *pNextVarEndOffset =
00551         referenceIndirectOffset(pTupleBufDest,iFirstVarEndIndirectOffset);
00552 
00553     for (uint i = 0; i < tuple.size(); i++) {
00554         uint iAttr;
00555         if (bAlignedVar) {
00556             iAttr = marshalOrder[i];
00557         } else {
00558             iAttr = i;
00559         }
00560         TupleDatum const &value = tuple[iAttr];
00561         AttributeAccessor const &accessor = getAttributeAccessor(iAttr);
00562         if (!isMAXU(accessor.iNullBit)) {
00563             bitFields[accessor.iNullBit] = value.pData ? false : true;
00564         }
00565         if (value.pData) {
00566             if (isMAXU(accessor.iValueBit)) {
00567                 uint iOffset;
00568                 if (!isMAXU(accessor.iFixedOffset)) {
00569                     iOffset = accessor.iFixedOffset;
00570                 } else {
00571                     iOffset = iNextVarOffset;
00572                 }
00573                 assert(value.cbData <= accessor.cbStorage);
00574                 accessor.marshalValueData(
00575                     pTupleBufDest + iOffset,
00576                     value);
00577             } else {
00578                 bitFields[accessor.iValueBit] =
00579                     *reinterpret_cast<bool const *>(value.pData);
00580             }
00581         } else {
00582             // if you hit this assert, most likely the result produced a null
00583             // but type derivation in SqlValidator derived a non-nullable
00584             // result type
00585             assert(!isMAXU(accessor.iNullBit));
00586         }
00587         if (!isMAXU(accessor.iEndIndirectOffset)) {
00588             assert(pNextVarEndOffset ==
00589                 referenceIndirectOffset(accessor.iEndIndirectOffset));
00590             if (value.pData) {
00591                 iNextVarOffset += value.cbData;
00592             }
00593             // regardless of whether the value is null, we need to record the
00594             // end offset since it also marks the start of the next
00595             // non-null value
00596             if (format == TUPLE_FORMAT_NETWORK) {
00597                 *pNextVarEndOffset =
00598                     htons(static_cast<StoredValueOffset>(iNextVarOffset));
00599             } else {
00600                 *pNextVarEndOffset = iNextVarOffset;
00601             }
00602             pNextVarEndOffset++;
00603         }
00604     }
00605     if (!isMAXU(iBitFieldOffset)) {
00606         // TODO:  trick dynamic_bitset to avoid copy
00607         boost::to_block_range(
00608             bitFields,
00609             pTupleBufDest + iBitFieldOffset);
00610     }
00611 }
00612 
00613 FENNEL_END_CPPFILE("$Id: //open/dev/fennel/tuple/TupleAccessor.cpp#18 $");
00614 
00615 // End TupleAccessor.cpp

Generated on Mon Jun 22 04:00:21 2009 for Fennel by  doxygen 1.5.1