Quickly (un)comment blocks of code in Rust - rust

In languages such as Java, I often use the following pattern for quickly commenting/uncommenting whole blocks of code:
/* *
hello.world();
/* */
// I just have to add one '/' and the block is uncommented:
/* */
hello.world();
/* */
However, in Rust, the above code creates a syntax error, as it is not allowed to have unequal numbers of /* and */ in a Rust file.
But is there a similar way for quickly commenting/uncommenting blocks in Rust that does not involve using editor macro-commands?

You can use single-line comments to activate/deactivate your multi-lines comment, e.g.
/*
commented_out();
// */
//*
not_commented();
// */

Related

How to escape a closing tag in block comments /** */?

I want to have an example regex in a comment:
/**
* Example = ".*/full/.*" }}`
*/
pub fn my_fun() {}
I get a broken comment since */ is considered as ending the comment.
What would be a proper way to escape this so that some autogenerated docs don't display the escape character?
You can do something like
/**
* Example = ".\*\/full/.*" }}
*/
pub fn my_fun(){}
It'll get rendered as
This should do.
But the recommended ways in rust are
https://doc.rust-lang.org/book/ch03-04-comments.html
https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments

using a globals struct in several .cpp files, and initializing it in the constructor

I know similar questions have been asked, but none address this issue. I want to create a globals struct and initialize it with default values. I implemented it as below, but the project won't build.
I've tried everything I can think of, most notably moving the "extern" declaration of *gxg in and out of the header guard and changing the struct to a class, but get the same results: the project won't build because of duplicate symbols for the globals constructor. It builds if I don't use it in more than one .cpp file, or if I don't include a constructor or destructor in the struct's implementation file.
// globals.hpp
#ifndef globals_hpp
#define globals_hpp
struct gxGlobals{
double radius;
bool easement;
gxGlobals(); // constructor
} ;
extern "C" gxGlobals *gxg;
#endif /* globals_hpp */
—————————————
// globals.cpp
#include "globals.hpp"
gxGlobals::gxGlobals():
radius(24),
easement(false)
{};
———————————
// main_file.cpp
#include "globals.hpp"
gxGlobals *gxg = new gxGlobals();
———————————
// other_file.cpp
#include "globals.hpp"
// ERROR: Duplicate symbol gxGlobals::gxGlobals()
I can include globals.h in one file, but not in two or more. It also works if I remove the self-initialization in the .cpp file.
There are too many members in the actual struct to make an initializer list practical, so my last option is a function that runs on startup that plugs all of the default values in. Am I mistaken that this should work?

Why doesn't MSVC initialize this const struct?

I have some code written in C, and there is one section that refuses to cooperate when using Visual Studio 2015 Community (clang has no problems). I have a simple struct:
/** Options for enumerating over all documents. */
typedef struct {
unsigned skip; /**< The number of initial results to skip. */
C4EnumeratorFlags flags; /**< Option flags */
} C4EnumeratorOptions;
enum {
kC4Descending = 0x01, /**< If true, iteration goes by descending document IDs. */
kC4InclusiveStart = 0x02, /**< If false, iteration starts just _after_ startDocID. */
kC4InclusiveEnd = 0x04, /**< If false, iteration stops just _before_ endDocID. */
kC4IncludeDeleted = 0x08, /**< If true, include deleted documents. */
kC4IncludeNonConflicted = 0x10, /**< If false, include _only_ documents in conflict. */
kC4IncludeBodies = 0x20 /**< If false, document bodies will not be preloaded, just
metadata (docID, revID, sequence, flags.) This is faster if you
don't need to access the revision tree or revision bodies. You
can still access all the data of the document, but it will
trigger loading the document body from the database. */
};
typedef uint16_t C4EnumeratorFlags;
And I also have a constant "default" value for it:
// In header
extern const C4EnumeratorOptions kC4DefaultEnumeratorOptions;
// In implementation
const C4EnumeratorOptions kC4DefaultEnumeratorOptions = {
0, // skip
kC4InclusiveStart | kC4InclusiveEnd | kC4IncludeNonConflicted | kC4IncludeBodies
};
However, when debugging I noticed that the initialization is not doing anything when I try to use the default value:
// options winds up with a "skip" value of something like 117939945
// and a flags value of 59648
C4EnumeratorOptions options = kC4DefaultEnumeratorOptions;
The section defining is in a DLL, and the second using is in an exe. Again, this only happens on Windows. Furthermore, the value in "options" is garbage but for some reason it's not even the same garbage that is stored in kC4DefaultEnumeratorOptions. I know MSVC is notorious for snubbing C, but this kind of initialization is so old that even MSVC should get it right, shouldn't it? So it must be something I am doing but I can't figure out what.
EDIT The symbol is being exported via a export definitions file. I checked with dumpbin, and found the symbol in the exported symbols list
41 46 00A6EA8 kC4DefaultEnumeratorOptions = kC4DefaultEnumeratorOptions
Also as one more bit of info, the calling code is C++ and the DLL code is C, which I suspect may be playing a part in this madness.
The comments from #M.M helped put me in the right direction. He asked if the symbol was exported. Technically, yes, it was exported since it was in the export list but apparently I also need to export the definition. So instead of including the global symbol in the .def file, I need to manually mark it with __declspec(dllexport) or __declspec(dllimport) in two places so in the end it looks like this:
#ifdef _MSC_VER
#ifdef CBFOREST_EXPORTS
#define CBFOREST_API __declspec(dllexport)
#else
#define CBFOREST_API __declspec(dllimport)
#endif
#endif
// ...
// Header
CBFOREST_API extern const C4EnumeratorOptions kC4DefaultEnumeratorOptions;
// Implementation
CBFOREST_API const C4EnumeratorOptions kC4DefaultEnumeratorOptions = {
0, // skip
kC4InclusiveStart | kC4InclusiveEnd | kC4IncludeNonConflicted | kC4IncludeBodies
};

Dynamically-Allocated Implementation-Class std::async-ing its Member

Consider an operation with a standard asynchronous interface:
std::future<void> op();
Internally, op needs to perform a (variable) number of asynchronous operations to complete; the number of these operations is finite but unbounded, and depends on the results of the previous asynchronous operations.
Here's a (bad) attempt:
/* An object of this class will store the shared execution state in the members;
* the asynchronous op is its member. */
class shared
{
private:
// shared state
private:
// Actually does some operation (asynchronously).
void do_op()
{
...
// Might need to launch more ops.
if(...)
launch_next_ops();
}
public:
// Launches next ops
void launch_next_ops()
{
...
std::async(&shared::do_op, this);
}
}
std::future<void> op()
{
shared s;
s.launch_next_ops();
// Return some future of s used for the entire operation.
...
// s destructed - delayed BOOM!
};
The problem, of course, is that s goes out of scope, so later methods will not work.
To amend this, here are the changes:
class shared : public std::enable_shared_from_this<shared>
{
private:
/* The member now takes a shared pointer to itself; hopefully
* this will keep it alive. */
void do_op(std::shared_ptr<shared> p); // [*]
void launch_next_ops()
{
...
std::async(&shared::do_op, this, shared_from_this());
}
}
std::future<void> op()
{
std::shared_ptr<shared> s{new shared{}};
s->launch_next_ops();
...
};
(Asides from the weirdness of an object calling its method with a shared pointer to itself, )the problem is with the line marked [*]. The compiler (correctly) warns that it's an unused variable.
Of course, it's possible to fool it somehow, but is this an indication of a fundamental problem? Is there any chance the compiler will optimize away the argument and leave the method with a dead object? Is there a better alternative to this entire scheme? I don't find the resulting code the most intuitive.
No, the compiler will not optimize away the argument. Indeed, that's irrelevant as the lifetime extension comes from shared_from_this() being bound by decay-copy ([thread.decaycopy]) into the result of the call to std::async ([futures.async]/3).
If you want to avoid the warning of an unused argument, just leave it unnamed; compilers that warn on unused arguments will not warn on unused unnamed arguments.
An alternative is to make do_op static, meaning that you have to use its shared_ptr argument; this also addresses the duplication between this and shared_from_this. Since this is fairly cumbersome, you might want to use a lambda to convert shared_from_this to a this pointer:
std::async([](std::shared_ptr<shared> const& self){ self->do_op(); }, shared_from_this());
If you can use C++14 init-captures this becomes even simpler:
std::async([self = shared_from_this()]{ self->do_op(); });

ctags generator for CORBA IDL?

I work in a multi-language environment and use Vim + ctags for navigating the code. However we also use CORBA and exuberant ctags does not parse IDL files.
Does anyone know of a ctags compatible tags generator for IDL?
If you use a simple regexp parser then it is a fairly trivial exercise to extend Exuberant Ctags to support another language.
For example, below is an example of a regexp parser taken from the Exuberant Ctags parser page:
/***************************************************************************
* make.c
* Regex-based parser for makefile macros
**************************************************************************/
/* INCLUDE FILES */
#include "general.h" /* always include first */
#include "parse.h" /* always include */
/* FUNCTION DEFINITIONS */
static void installMakefileRegex (const langType language)
{
addTagRegex (language, "(^|[ \t])([A-Z0-9_]+)[ \t]*:?=", "\\2", "m,macro", "i");
}
/* Create parser definition stucture */
extern parserDefinition* MakefileParser (void)
{
static const char *const patterns [] = { "[Mm]akefile", NULL };
static const char *const extensions [] = { "mak", NULL };
parserDefinition* const def = parserNew ("Makefile");
def->patterns = patterns;
def->extensions = extensions;
def->initialize = installMakefileRegex;
def->regex = TRUE;
return def;
}
It's quite easy to add another language to ctags using a few regular expressions and the ctags configuration file.

Resources