// // The following program illustrates how to use references to search for // items in "geners" archives together with the various methods that // can be used to retrieve the items // #include #include #include "geners/StringArchive.hh" #include "geners/Record.hh" #include "geners/Reference.hh" using namespace gs; using namespace std; // We will use the following function to print out the items found // in the archive by an archive reference. All items considered in // this example are simple strings. // static void print_items(const Reference& ref) { // Total number of items found by the reference const unsigned long nItems = ref.size(); // Print the info about the reference to the standard output cout << "Found " << nItems << " item" << (nItems == 1 ? "" : "s") << " in the archive using name pattern \"" << ref.namePattern().pattern() << '"' << (ref.namePattern().useRegex() ? " (regex)" : " (exact)") << "\nand category pattern \"" << ref.categoryPattern().pattern() << '"' << (ref.categoryPattern().useRegex() ? " (regex)" : " (exact)") << (nItems ? ":\n" : ".\n"); // Cycle over the items found, retrieve them from the archive, // and print them for (unsigned long i=0; i ref1(ar, "hello", "Greetings"); assert(ref1.unique()); print_items(ref1); // What happens if name/category combination does not // exist? The reference "size()" method will return 0 // and "empty()" will return "true". // cout << "\n** What if name/category combination does not exist?" << endl; Reference ref2(ar, "no such name", "Greetings"); assert(ref2.empty()); print_items(ref2); // What happens if more than one item exists with the given // name/category combination? The reference will simply // collect all such items. // cout << "\n** What if there is more than one item " << "with given name/category?" << endl; Reference ref3(ar, "classics", "Movies"); print_items(ref3); // Archive references support regular expressions for names // and categories. If the "geners" package was compiled with // a C++11-enabled compiler, the standard C++11 "regex" engine // is used, otherwise POSIX extended regular expressions are used. // Note that the default mode of C++11 regex is "ECMAScript" // which is somewhat different from POSIX extended regular // expressions. If you really want to know the details of the // ECMAScript regex syntax, read the "RegExp" section of // http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf // // The number of operations needed to search for an item in // an archive using exact name and category typically scales as // O(log(C) + log(N)), where C is the number of categories and N // is the number of items in the category to which the item belongs. // If regular expressions are used, the scaling behavior changes. // In general, this behavior depends on the details of the archive // catalog implementation. The catalogs currently implemented // in the "geners" package typically need O(N*log(C)) // operations if regular expression search is used for item name // only, O(C_m*log(N)) if regular expression search is used for // category only (where C_m is the number of categories matching // the expression), and O(C_m*N) if regular expressions are used // for both name and category. Therefore, regex searching can take // a considerable amount of time for large catalogs. // // In the examples below, a special constructor is used for the // "SearchSpecifier" objects with which references are made. // This is because we want to be able to print the regular // expressions used, and C++11 regular expressions do not // have a method to retrieve the original expression string // from them. When this special constructor is used, // "SearchSpecifier" stores this string for subsequent retrieval. // cout << "\n** Regex example -- arbitrary name" << endl; Reference ref4(ar, SearchSpecifier(".*", true), "Greetings"); print_items(ref4); cout << "\n** Regex example -- same search, but using regex argument " << "directly. Note\n that the regular expression itself can no " << "longer be extracted from such\n an argument. This example " << "prints an empty string instead." << endl; Reference ref5(ar, Regex(".*"), "Greetings"); print_items(ref5); cout << "\n** Regex example -- arbitrary category" << endl; Reference ref6(ar, "quantum", SearchSpecifier(".*", true)); print_items(ref6); cout << "\n** Regex example -- name matching a substring, " << "arbitrary category" << endl; Reference ref7(ar, SearchSpecifier("(.*)movie(.*)", true), SearchSpecifier(".*", true)); print_items(ref7); // There are three main methods by which items can be retrieved from // the archive: // // 1. Overwrite another item of the same type present on the stack. // This method is appropriate for built-in types, standard // containers, and user-defined classes or templates that have // a default constructor (in addition, these classes or templates // should not be members of any inheritance hierarchy). // // 2. Get a unique pointer (std::unique_ptr for C++11, std::auto_ptr // before that) to an item built on the heap. "geners" package // uses "CPP11_auto_ptr" macro to name such a unique pointer. // This method is most typical for types that do not have a default // constructor or for members of some inheritance hierarchy. Items // of derived types can be retrieved using a pointer to their base // class if they are stored in the archive by reference to the base // class. // // 3. Get a shared pointer (std::shared_ptr for C++11, std::tr1::shared_ptr // before that) to an item built on the heap. "geners" package // uses "CPP11_shared_ptr" macro to name such a shared pointer. // Use this method whenever joint item ownership via a shared // pointer is appropriate for your code. // // Method 1 is how the "print_items" function defined earlier in this // file retrieves the strings from the archive. The following code // illustrates the other two methods. // cout << "\n** Placing an item on the heap using a unique pointer" << endl; CPP11_auto_ptr p1 = ref1.get(0); cout << *p1 << endl; cout << "\n** Placing an item on the heap using a shared pointer" << endl; CPP11_shared_ptr p2 = ref1.getShared(0); cout << *p2 << endl; // We are done return 0; }