I am one of the few that actually owned one (The Exidy Sorceror). I bought it with money I made working summer jobs in high school. For the time, it had some very interesting features. Like the TRS-80, it didn't really have a graphics mode, but used characters to draw graphics on the screen. Unlike the TRS-80, the top 128 characters were mapped to RAM, so you could replace them at the pixel level. There were a number of games for the Sorceror that were based on arcade games, and they looked just like the arcade games because of the character set remapping. John
jbarton
Posts
-
A trip down memory lane. -
You'll be glad to know! [modified]I wouldn't be trying to beat those criteria as they don't match the style that I prefer. I would instead refactor this to use a helper routine:
bool ShouldPointBeRemoved(List points, int i)
{
var v1 = new Vector2D(points[i > 0 ? i - 1 : points.Count - 1], points[i]);
var v2 = new Vector2D(points[i], points[i < points.Count - 1 ? i + 1 : 0]);
if (v1.SquareNorm <= MINL || v2.SquareNorm <= MINL)
return true;v1 = v1.Normalize(); v2 = v2.Normalize(); var z = v1 ^ v2; return (Math.Abs(z) <= minsin && v1 \* v2 < 0);
}
Note: I used a List for the points, as you never specified a type. Once this helper routine is provided, the loop becomes:
for (int i = max; i >= min; i--)
{
if (ShouldPointBeRemoved(points, i))
{
points.RemoveAt(i);
if (points.Count < 3)
return null;
}
}I find that this refactoring is much easier to read than the original code, as the loop now clearly shows its intent. If you really don't like extra indent level in the loop, you could use a continue:
for (int i = max; i >= min; i--)
{
if (! ShouldPointBeRemoved(points, i))
continue;
points.RemoveAt(i);
if (points.Count < 3)
return null;
} -
this (another C# programmer rant)I wish I could disable this warning. It was a decision from higher up that StyleCop would be used pretty much as is (a few warnings have been turned off, but for the most part they are all on). There is a check-in policy that says that there can't be any StyleCop warnings based on the global team settings. I can't turn it off just for my machine or I would get warnings and the check-in would fail.
-
this (another C# programmer rant)I am not a fan of "this." as a prefix (coming from a C++ background). The place that I work at does new development in C# and has decided to use the Microsoft StyleCop to check the code style. One of the rules of the StyleCop is that member access must be prefixed by "this.". Apparently this is the Microsoft recommended way of indicating member variable access. John
-
Directory.GetFiles oddity.The result of Directory.GetFiles("c:") is well defined. You get the same result as if you typed "dir c:" from a command prompt. The result is the contents of the current directory on the c drive. The result of Directory.GetFiles(@"c:\") is the contents of the root directory. If you leave off the '\', Directory.GetFiles() will return a relative path to the current directory on the specified drive. So, Directory.GetFiles(@"c:\blah") is the contents of the blah directory off of the root and Directory.GetFiles(@"c:blah") is the contents of the blah directory off of the current directory on the c drive. If you leave off the drive, Directory.GetFiles() will return either an absolute or relative path on the current drive. So, Directory.GetFiles(@"\blah") is the contents of the blah directory on the current drive and Directory.GetFiles(@"blah") is the contents of the blah directory off of the current directory of the current drive.
-
When a feature sucks...It wasn't me, but the link is http://www.addintools.com/english/menuoffice/default.htm[^]
-
Hungarian Notation in .Net - Yes or No?There are much better uses for var than the just for lazy programmers. One good example of where it will help is with the new LINQ support. LINQ allows the generation of new data types as the result of a query. See http://blogs.msdn.com/danielfe/archive/2005/09/22/472884.aspx[^] for an example.
-
Forced scoping as a programming technique?I didn't read your reply until this morning, so I am just replying now. Looking at your PROCESS macro, it seems like most of it could easily be changed to be a member template function of class MainWindow (although I am making some assumptions about what the various symbols are). The assumptions that I am making are: - CallbackWrapperSpecific is a templated class derived from CallbackWrapperGeneric. - The args passes to PROCESS is a specific variable with the type matching the first argument passed to PROCESS. - The PROCESS macro is being used inside a member of MainWindow. I assume this because the "this" pointer is being passed to the constructor of CallbackWrapperSpecific. - The m_localWorkMap is a member of MainWindow which is used to hold thread ids which map to CoreWorkUnit * objects (part of your cleanup mechanism). - The m_threadPool is a member of MainWindow which is used to create a thread to process the request, with its Process member returning the thread id. Given these assumptions, the only problem line that I see in the entire macro is: CoreWorkUnit* cWorkUnit = new CoreWorkUnit(Function_##function, cbwDest); This line is constructing a Function_ name from a combination of a constant string and the name of the member routine in MainWindow. This appears to be the only line which can't directly be converted into using a member template function. If you could explain what this is for, perhaps I could suggest another way to do this. The rest of the code looks straight forward and should be easy to change - the following is close to what would be used (if my assumptions were correct):
template void Process( void (MainWindow::*memberFn)(type&), type args ) { CallbackWrapperSpecific< MainWindow, void (MainWindow::*)(type&), type >* cbwSpecific = new CallbackWrapperSpecific< MainWindow,void(MainWindow::*)(type&), type>( this, memberFn, args ); CallbackWrapperGeneric* cbwGeneric = cbwSpecific; CallbackWrapperDestroy* cbwDest = cbwSpecific; CoreWorkUnit* cWorkUnit = new CoreWorkUnit(/*Function_##function,*/ cbwDest); m_localWorkMap.insert(map::value_type(m_threadPool->Process(cbwGeneric), cWorkUnit)); }
Note that I commented out the first argument to the CoreWorkUnit constructor as I didn't know what to put here. The calling sequence is slightly different, as you pass the type as a template parameter, and the address of the MainWindow routine as the fir -
Forced scoping as a programming technique?The main point I was trying to get across was that you should avoid using macros in C++ except in a very small number of special cases. Using macros is generally the C method of doing things, not the C++ method. Whether you make the routine that replaces the macro into an inline routine or just a callable routine is not important. I only suggested an inline routine since it produces almost exactly the same result as a macro - no additional function call being made in the generated code. You would get the same benefits with a normal routine instead of an inline routine except the generated code would probably include a call to this normal routine. Note: some compilers may choose to inline a small normal routine without you adding the inline keyword. Also, some routines marked as inline might still result in a function call - the compiler doesn't have to inline a routine when you tell it to inline. This generally doesn't happen, but there are a few cases where it is needed (such as if you get a pointer to the inline routine and then call it through the pointer). The usage of smart pointers may or may not be appropriate in your case. It just tends to make the cleanup code a lot easier. As long as you can arrange to have the scope of the variable end when you no longer need the resource, then you don't need to do any explicit calls to delete the object. Sometimes it just takes a little reorganization to take advantage of smart pointers. Without seeing your code, I can't tell whether you could use smart pointers by just rearranging things a bit. You said that you were placing the pointers into an STL collection for future cleanup. You could place a boost::shared_ptr into the collection, which would simplify the eventual cleanup. Instead of needing to loop through the collection and manually deleting each pointer, you can just clear the collection. The boost::shared_ptr would then take care of cleanup automatically.
-
Forced scoping as a programming technique?You said that you are using an STL container to keep track of pointers. Since you are using C++, you really should consider changing from using macros to instead use inline routines. Except for certain special diagnostic or logging routines (where you want to access preprocessor macros such as __FILE__ or __LINE__), there normally isn't any need to use macros in C++ for blocks of code. In this case, it sounds like you should just make a small inline routine which declares and initializes the variables needed to call your other routine. This small routine can then be used as many times as you want, as the scope of the variables are within the routine. By making it inline, there should be no additional overhead beyond what you would get from a macro. You also won't need to pass in a number as a token parameter, as you won't get variable redefinitions if you use an inline routine instead of a macro. As far as keep tracking of pointers to delete, I would suggest that you instead use an appropriate smart pointer, using the lightest weight smart pointer that you can. For many simple cases, an std::auto_ptr is sufficient or even a boost::scoped_ptr will work. For more complicated cases, a reference counting smart pointer such as boost::shared_ptr might be needed. Without knowing how you are using the pointers, I couldn't tell which would be a better choice.
-
Missing '=' in if-statementyou can change the level for specific warnings using a pragma: #pragma warning( 3 : 4706 ) This will change the level of warning 4706 to 3 so that it will report: warning C4706: assignment within conditional expression when the warning level is 3.
-
The First Program You Ever WroteFrom what I remember, the TRS-80 had a very crude form of "graphics". While it really always stayed in text mode, 64 characters in the character set were special 3 high by 2 wide pixel characters. This allowed setting monochrome pixels on the screen (as long as they didn't overlap with where you wanted to put text). I think the text display was 80 by 24, which allowed for an effective graphics resolution of 160 by 72. I remember an early game called 'Android Nim' which used the crude graphics to display animation of Android characters which were destroyed as part of playing the game. The game itself was very simple, but it was fun to see animation on a TRS-80. I think that the source was printed in some magazine of the time (the late 70's). At the time, I had an Exidy Sorceror computer (another Z-80 based computer which also had Basic available). It didn't have the TRS-80 character set for graphics, but it did have a programmable character set (you could poke data into the character set for the top 128 characters). I ported a number of TRS-80 games to the Exidy (including Android Nim) by setting up the programmable characters with a character set similar to the TRS-80.
-
__int64 questionI prefer to write a global operator>> and operator<< for datatypes like this, so that I can still use the syntax of a stream operator with the archive.
CArchive& operator<<( CArchive& archive, __int64 value ) { archive.Write( &value, sizeof(__int64) ); return archive; } CArchive& operator>>( CArchive& archive, __int64 value ) { archive.Read( &value, sizeof(__int64) ); return archive; }
This works for simple data types. I use this for bool as VC6.0 doesn't implement serialization for bool, but this should also work fine for __int64. Best regards, John -
visual c++ funny or its a bug?Modifying var more than once between sequence points results in undefined behavior in C++. A C++ compiler can generate whatever results it wants from this. You could get 100, 110, 121, or any other value. Any result produced can't be considered correct or wrong - it is undefined.
-
Funny C++In the second and third cout statements, you are modifying the value of i more than 1 time between sequence points. The result of this is undefined behavior - the compiler can output anything it wants.
-
STL "for_each" algorithm.I think the idea of iterating through the map to update multiple elements has merit. If (for instance) I want to update the data associated with all keys that match a particular pattern, there really isn't any way that I could do it without iterating through all elements in the map. When I have a list of specific key values whose data I want to update, I find it difficult to set up a functor that efficiently checks for these key values and then updates the associated data values. It may be possible using another map or hash within the functor to lookup the key value and then get the replacement value. With only simple if / else if comparisons, I think that the overhead of the functor would probably remove any advantage gained by not using find on each key value. Unless the program I was writing was running too slowly and by profiling I found it to be due to using find to update the map, I would probably stick with using find. If you know of a better way of writing this functor, let me know. I am always interested in hearing other approaches. Best regards, John
-
STL "for_each" algorithm.The code example provided by Jörgen Sigvardsson was correctly updating a map of ints. It is easy to change this example to work with strings.
#include <map> #include <iostream> #include <utility> #include <algorithm> #include <string> typedef std::map<std::string,std::string> StringMap; struct update { void operator() ( StringMap::value_type& v ) const { if ( v.first == "second" ) v.second = "replaced value"; } }; struct print { void operator() ( StringMap::value_type& v ) const { std::cout << "first = " << v.first << ", second = " << v.second << std::endl; } }; int main( int argc, char* argv[] ) { StringMap testMap; testMap.insert( StringMap::value_type("first", "1") ); testMap.insert( StringMap::value_type("second", "2") ); testMap.insert( StringMap::value_type("third", "3") ); testMap.insert( StringMap::value_type("fourth", "4") ); testMap.insert( StringMap::value_type("fifth", "5") ); std::for_each(testMap.begin(), testMap.end(), print()); std::for_each(testMap.begin(), testMap.end(), update()); std::for_each(testMap.begin(), testMap.end(), print()); return 0; }
However, as you know (from your comments in your original post), the code in the "update" functor is basically doing a find. However, since the for_each does a loop through all elements of the map, this is much less efficient than doing an actual find. If you need to do single updates to elements in a map which have particular key values, it would normally be better to just do the find and then update the element. The for_each algorithm is really only appropriate if you need to access every element in the container. Best regards, John -
STL list sort() limitIt looks like there is a bug in the list sort routine which ships with VC 6.0. Looking at the source in , it appears that the internal array used to process the merge sorts is not being handled properly when the array is full. You might be able to find a fix for this by getting an upgrade to the STL that you use. This isn't a bad idea, as there are a number of problems with the STL that ships with VC 6.0. For a quick fix, you could patch the header file so that the sort works correctly. Or you could write your own sort routine which fixes the problem. (just glancing at it, it appears that the sort could be fixed by changing the following sequence:
if (_I == _MAXN) _A[_I].merge(_X); else {_A[_I].swap(_X); if (_I == _N) ++N; }}
to the following:if (_I == _MAXN) _A[_I].merge(_X); else _A[_I].swap(_X); if (_I == _N) ++N; }
Note: I only briefly tested this, but it appears to work. The other choice (if you are going change ) is to increase the const _MAXN to a larger number, so that the temporary array can fit more elements. Each increase of this number doubles the size of the list that can be sorted. By setting this to 32, it should be able to handle any size list that you could create. Best regards, John -
MFC Menu Graying.The normal MFC way of enabling/disabling menu items during runtime is to implement the UPDATE_COMMAND_UI handler for the item. To do this, use the class wizard to add an UPDATE_COMMAND_UI message handler for the particular menu item that you want to handle: - On the "Message Maps" page, select the object id of the menu item that you want to control - select the UPDATE_COMMAND_UI in the Messages window. - Click on the "Add Function" button to add a handler for it. - Click on the "Edit Code" button to goto the code for the newly added handler. In the handler code, you can control whether the menu item is enabled or disabled as follows: - To enable the menu item, call pCmdUI->Enable( TRUE ); - To disable the menu item, call pCmdUI->Enable( FALSE );
-
Will sort method in STL cause memory disorder?For the way that you defined your struct str_info, you also need to implement operator=. However, I would suggest that you use a vector as the occ_pos member, and don't bother with either the copy constructor or assignment operator. If all the members of your str_info struct support assignment and copy constructor, you won't need to implement these. Best regards, John