class FileNode : public boost::intrusive::list_base_hook<link_mode<auto_unlink> > { private: boost::filesystem::path name; // file name char type; // f is file, d is directory public: boost::intrusive::list< FileNode, base_hook<list_base_hook<link_mode<auto_unlink> > >, constant_time_size<false> > sibling; };I created a FileNode class represent the file in a path, and each object of this class can neither be a file or a folder, and the a name too. These are the private member declared in the class. The sibling member is to tell whether they are any sub directory available, if the size is greater than zero, it means there are files in it.
Now come to the main dish. There are 2 part of it; first would be the load the given path into the memory by using the class structure mention above, second is to constructed of the files underneath the given path. For this POC, I'm focusing on the first part, the second part has not yet done.
I have though should I skip the first part for some while? Say when user keyed in /home/path_1, can I just treat the value as a single FileNode? Since I doesn't really care what the value are, it would be easier for me to do the job. Coming from the perfectionism view-point, I think it would be nice to load every single file entity as a separate FileNode object. Meaning to said that /home is one object, and /path_1 is another object.
For this purpose, I create a function to handle this job for me.
FileNode* FileBot::constructParentPath(string path) { vector<string> words; FileNode *node = new FileNode(); string unixFilePath = path; boost::replace_last(unixFilePath, "/", "|"); boost::split(words, unixFilePath, boost::is_any_of("|"), boost::token_compress_on); node->setType('d'); node->setName(words[1]); // there is a parent node if( words[0] != "" ) { FileNode *parent = constructParentPath(words[0]); cout << "parent address: " << parent << endl; parent->sibling.push_back(*node); } else { fileList.push_back(*node); cout << "node address: " << node << " " << node->getName() << endl; } words.clear(); return node; }This function is as good as it works only on Linux, but failed on Windows. It can't pass the test case in Windows specific path. After many round of rework, then only I figure out a new solution that tested out on both Linux and Windows:
int FileBot::initialize() { // bail out if the path doesn't exists if( !exists(fileNode.getName().generic_string()) ) return 0; // construct the parent path first string path = fileNode.getName().generic_string(); FileNode *parent = NULL; typedef split_iterator<string::iterator> string_split_iterator; for( string_split_iterator it = make_split_iterator(path, first_finder("/", is_equal())); it != string_split_iterator(); ++it) { FileNode *node = new FileNode(); node->setType('d'); node->setName(copy_range<string>(*it)); cout << "value inserted: [" << copy_range<string>(*it) << "]" << endl; if( parent == NULL ) { fileList.push_back(*node); } else parent->sibling.push_back(*node); parent = node; cout << "parent: " << parent; cout << " parent value: " << parent->getName(); cout << " sibling size: " << parent->sibling.size() << endl; } return 1; }The difference between the 2 solutions is that the first one is using the recursive loop and the later one is using for loop. On top of that the second solution is much easier to read than the first. To check my work is being done correctly, I have created following test case for the unit test.
/* load 1 level parent path * */ BOOST_AUTO_TEST_CASE(TL_4) { BOOST_TEST_MESSAGE("TC4 : load 1 level parent path"); #if defined(WIN32) BOOST_TEST_MESSAGE("Test path: D:"); FileBot fb("D:"); #else BOOST_TEST_MESSAGE("Test path: /home"); FileBot fb("/home"); #endif string path = ""; if( fb.initialize() == 1 ) path = fb.verifyFileList(); #if defined(WIN32) BOOST_TEST(path == "D:"); fb.clearMemory(); #else BOOST_TEST(path == "/home"); #endif } /* load 2 level parent path * */ BOOST_AUTO_TEST_CASE(TL_5) { BOOST_TEST_MESSAGE("TC5 : load 2 level parent path"); #if defined(WIN32) BOOST_TEST_MESSAGE("Test path: D:/workspaceqt"); FileBot fb("D:/workspaceqt"); #else BOOST_TEST_MESSAGE("Test path: /home/kokhoe"); FileBot fb("/home/kokhoe"); #endif string path = ""; if( fb.initialize() == 1 ) path = fb.verifyFileList(); #if defined(WIN32) BOOST_TEST(path == "D:/workspaceqt"); fb.clearMemory(); #else BOOST_TEST(path == "/home/kokhoe"); #endif } /* load 3 level parent path * */ BOOST_AUTO_TEST_CASE(TL_6) { BOOST_TEST_MESSAGE("TC6 : load 3 level parent path"); #if defined(WIN32) BOOST_TEST_MESSAGE("Test path: D:/workspaceqt/ui1"); FileBot fb("D:/workspaceqt/ui1"); #else BOOST_TEST_MESSAGE("Test path: /home/kokhoe/workspaceqt"); FileBot fb("/home/kokhoe/workspaceqt"); #endif string path = ""; if( fb.initialize() == 1 ) path = fb.verifyFileList(); #if defined(WIN32) BOOST_TEST(path == "D:/workspaceqt/ui1"); fb.clearMemory(); #else BOOST_TEST(path == "/home/kokhoe/workspaceqt"); #endif }
No comments:
Post a Comment