sapling/remotefilelog/ctreemanifest/manifest.cpp
Tony Tung 5e5270d3a7 [ctree] initialize the ManifestEntry in addChild after adding to the list
Summary: When a ManifestEntry is destroyed, we reap the heap-allocated resources it holds.  However, this (erroneously) happens when we create a ManifestEntry and add it to the list of children.  What we really need is a move constructor from C++11.  The workaround is to initialize a blank ManifestEntry, add it to the proper location, and then populate it afterwards.

Test Plan: addChild (in a later diff) no longer tramples over memory it no longer owns.

Reviewers: #fastmanifest, durham

Reviewed By: durham

Subscribers: mitrandir

Differential Revision: https://phabricator.intern.facebook.com/D3772915

Signature: t1:3772915:1472174144:a4baac5cb5f6e01a38042c5c6cd92570c8f8e100
2016-08-26 13:49:17 -07:00

107 lines
2.8 KiB
C++

// manifest.cpp - c++ implementation of a single manifest
//
// Copyright 2016 Facebook, Inc.
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
//
// no-check-code
#include "manifest.h"
Manifest::Manifest(PythonObj &rawobj) :
_rawobj(rawobj) {
char *parseptr, *endptr;
Py_ssize_t buf_sz;
PyString_AsStringAndSize(_rawobj, &parseptr, &buf_sz);
endptr = parseptr + buf_sz;
while (parseptr < endptr) {
ManifestEntry entry = ManifestEntry(parseptr);
entries.push_back(entry);
}
}
ManifestIterator Manifest::getIterator() {
return ManifestIterator(this->entries.begin(), this->entries.end());
}
/**
* Returns an iterator correctly positioned for a child of a given
* filename. If a child with the same name already exists, *exacthit will
* be set to true. Otherwise, it will be set to false.
*/
std::list<ManifestEntry>::iterator Manifest::findChild(
const char *filename, const size_t filenamelen,
bool *exacthit) {
for (std::list<ManifestEntry>::iterator iter = this->entries.begin();
iter != this->entries.end();
iter ++) {
size_t minlen = filenamelen < iter->filenamelen ?
filenamelen : iter->filenamelen;
// continue until we are lexicographically <= than the current location.
int cmp = strncmp(filename, iter->filename, minlen);
if (cmp == 0 && filenamelen == iter->filenamelen) {
*exacthit = true;
return iter;
} else if (cmp > 0 ||
(cmp == 0 && filenamelen > iter->filenamelen)) {
continue;
} else {
*exacthit = false;
return iter;
}
}
*exacthit = false;
return this->entries.end();
}
ManifestEntry *Manifest::addChild(
std::list<ManifestEntry>::iterator iterator,
const char *filename, const size_t filenamelen,
const char flag) {
ManifestEntry entry;
this->entries.insert(iterator, entry);
// move back to the element we just added.
--iterator;
// return a reference to the element we added, not the one on the stack.
ManifestEntry *result = &(*iterator);
result->initialize(filename, filenamelen, NULL, flag);
return result;
}
ManifestIterator::ManifestIterator(
std::list<ManifestEntry>::iterator iterator,
std::list<ManifestEntry>::const_iterator end) :
iterator(iterator), end(end) {
}
ManifestEntry *ManifestIterator::next() {
if (this->isfinished()) {
return NULL;
}
ManifestEntry *result = &(*this->iterator);
this->iterator ++;
return result;
}
ManifestEntry *ManifestIterator::currentvalue() const {
if (this->isfinished()) {
throw std::logic_error("iterator has no current value");
}
return &(*iterator);
}
bool ManifestIterator::isfinished() const {
return iterator == end;
}