// these will all be prefixed by the name of my portable library or an // abbreviation of it. class Object { virtual Object * clone() const = 0; // if the two objects are not of the exact same type // the assign method is undefined. virtual void assign(const Object *) = 0; virtual void error_num() {return 0;} virtaul const char * error_message() {return "";} ~Object() {} } // An emulation is an efficient way to iterate through elements much // like a forward iterator. The at_end method is a convince method and // as emulations will return a null pointer when they are at the end. // Unlike an iterator iterating through x elements on a list can be // done in x function calls while an iterator will require 3*x. // function calls. // Example of emulator usage // const char * word; // while ( (word = elements->next()) != 0) { // one function call // cout << word << endl; // } // And an iterator // iterator i = container->begin(); // iterator end = container->end(); // while (i != end) { // comparison, one function call // cout << *i << endl; // deref, total of two function calls // ++i; // increment, total of three function calls. // } // Normally all three calls are inline so it doesn't really matter // but when the container type is not visible there are not inline // and probably even virtual. // If you really love iterators you can very easily wrap an emulation // in a forward iterator. class StringEmulation : public Object { public: virtual const char * next() = 0; virtual bool at_end() const = 0; }; class StringPair { const char * first; const char * second; } class StringPairEmulation : public Object { public: virtual StringPair next() = 0; virtual bool at_end() const = 0; virtual ~StringPairEmulation() {} }; // Used by the Config class below... class MutableContainer { public: virtual void insert(const char *) = 0; virtual void remove(const char *) = 0; virtual void clear() = 0; virtual ~MutableContainer(); }; enum AddAction {Insert, Replace}; // A string map is a simple hash table where the key and values // are strings. It also has the ability to write and read data // files of a standard format. // It is perfect for storing word pairs for "Replace All". class StringMap : public MutableContainer, virtual public Object { public: PairEmulation * elements() const; // allocated with new virtual void insert(const char * key, const char * value) = 0; // note: insert will NOT overwrite an existing entry virtual void replace(const char * key, const char * value) = 0; virtual void remove(const char * key) = 0; virtual const char * lookup(const char * key) const = 0; virtual bool have(const char * key) const = 0; virtual void clear() = 0; virtual void merge(const StringMap & other); virtual void read_in_stream(istream &, char delim = '\n', AddAction a = Replace); virtual void read_in_file(const char *, AddAction a = Replace); virtual void read_in_string(const char *, AddAction a = Replace); virtual void write_to_stream(ostream &) const; virtual void write_to_file(const char *) const; }; struct KeyInfo { const char * name; enum Type {Bool, String, Int, List}; Type type; const char * def; const char * desc; // null if internal value }; class KeyInfoEmulation { ... }; // The Config class is used to hold configuration information. // it has a set of keys which it will except. Inserting are even // trying to look at a key that it does not know will produce // an error. Extra accepted keys can be added with the set_extra // method. class Config : public StringMap { public: private: void set_extra(const KeyInfo * begin, const KeyInfo * end); virtual const KeyInfo * keyinfo(const char * key) const = 0 virtual KeyInfoEmulation * possible_elements(bool include_extra = true) const = 0; // allocates with new virtual string get_default(const char * key) const = 0; // these unlike lookup will // a) return the default if the value is not set // b) give an error if the key is not requested as known // c) give an error if the value is not in the right format virtual string retrieve (const char * key) const = 0; virtual string retrieve_list (const char * key) const = 0; virtual void retrieve_list (const char * key, MutableContainer &) const = 0; virtual bool retrieve_bool(const char * key) const = 0; virtual int retrieve_int(const char * key) const = 0; // This will read in the configuration from a set of files and // environmental variables specific to the particular spell checker // used. void read_in(); }; // This class is responsible for keeping track of the dictionaries // coming up with suggestions and the like // Its methods are NOT meant to be used my multiple threads and/or // documents. // Most all if the manipulation of options is done via the Config // class, thus this class has precious few methods class Manager : public Object { virtual Config & config() = 0; virtual const Config & config () const = 0; virtual const char * lang_name() const = 0; bool check(const char * word) const; void add_to_personal(const char *); void add_to_session(const char *); void save_all_wls(); void clear_session(); SuggestionList & suggest(const char * word); // the suggestion list and the elements in it are only // valid until the next call to suggest. void store_repl(const char * mis, const char * cor); }; class SuggestionList : public Object { public: virtual bool empty() const = 0; virtual int size() const = 0; virtual StringEmulation * elements() const = 0; }; // these will also be some classes for checking a document which will // be about like it was in my original plan but I have not worked the // details of those classes out yet. // There will also be a bunch of functions that will return various // of the above classes allocated with new. // Stuff like sharing dictionaries between different Managers and the // like will be handles by these functions and by setting parameters in // the Config class. // Should I provide classes to directly access the individual word lists?