Commit 59fcaaff authored by Davis King's avatar Davis King

Reworked the config_reader interface a little to make it easier to use. In

particular, I removed the enumerator over blocks in favor of a simple
get_blocks() function that just returns a std::vector of all the blocks.
I also removed the requires clauses on the block and key accessor functions
and instead made a request for a non-existent key/block result in a non-fatal
exception.  This way users can let the config reader perform a more natural
role in config file validation (by catching this exception and acting accordingly).

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403077
parent 9ff5b39d
......@@ -31,29 +31,15 @@ namespace dlib
map<std::string,void*>::kernel_1b,
tokenizer::kernel_1a
> kernel_1a;
// kernel_1a_c
typedef config_reader_kernel_1<
map<std::string,std::string>::kernel_1b,
map<std::string,void*>::kernel_1b,
tokenizer::kernel_1a,
true
> kernel_1a_c;
#ifndef DLIB_ISO_CPP_ONLY
// thread_safe_1a
typedef config_reader_thread_safe_1<
kernel_1a,
map<std::string,void*>::kernel_1b,
false
map<std::string,void*>::kernel_1b
> thread_safe_1a;
// thread_safe_1a_c
typedef config_reader_thread_safe_1<
kernel_1a_c,
map<std::string,void*>::kernel_1b,
true
> thread_safe_1a_c;
#endif // DLIB_ISO_CPP_ONLY
};
......
This diff is collapsed.
......@@ -5,12 +5,11 @@
#include <string>
#include <iosfwd>
#include "../interfaces/enumerable.h"
namespace dlib
{
class config_reader : public enumerable<config_reader>
class config_reader
{
/*!
......@@ -18,11 +17,6 @@ namespace dlib
- there aren't any keys defined for this object
- there aren't any blocks defined for this object
ENUMERATION ORDER
The enumerator will iterate over the sub blocks in the config_reader.
They will be enumerated in sorted order according to the ordering
established on the block names by operator<.
POINTERS AND REFERENCES TO INTERNAL DATA
The destructor, clear(), and load_from() invalidate pointers
and references to internal data. All other functions are guaranteed
......@@ -92,7 +86,7 @@ namespace dlib
public:
// exception class
// exception classes
class config_reader_error : public dlib::error
{
/*!
......@@ -115,6 +109,28 @@ namespace dlib
const bool redefinition;
};
class config_reader_access_error : public dlib::error
{
/*!
GENERAL
This exception is thrown if you try to access a key or
block that doesn't exist inside a config reader.
!*/
public:
config_reader_access_error(
const std::string& block_name_,
const std::string& key_name_
);
/*!
ensures
- #block_name == block_name_
- #key_name == key_name_
!*/
const std::string block_name;
const std::string key_name;
};
// --------------------------
config_reader(
......@@ -207,48 +223,64 @@ namespace dlib
const std::string& block_name
) const;
/*!
requires
- is_block_defined(block_name) == true
ensures
- returns a const reference to the config_reader that represents the given named sub block
- if (is_block_defined(block_name) == true) then
- returns a const reference to the config_reader that represents the given named sub block
- else
- throws config_reader_access_error
throws
- config_reader_access_error
if this exception is thrown then its block_name field will be set to the
given block_name string.
!*/
const std::string& operator[] (
const std::string& key_name
) const;
/*!
requires
- is_key_defined(key_name) == true
ensures
- returns a const reference to the value string associated with the given key in
this config_reader's block.
- if (is_key_defined(key_name) == true) then
- returns a const reference to the value string associated with the given key in
this config_reader's block.
- else
- throws config_reader_access_error
throws
- config_reader_access_error
if this exception is thrown then its key_name field will be set to the
given key_name string.
!*/
template <
typename queue_of_strings
// Is an implementation of queue/queue_kernel_abstract.h with T set to std::string
>
void get_keys (
queue_of_strings& keys
) const;
/*!
requires
- queue_of_strings is an implementation of queue/queue_kernel_abstract.h
with T set to std::string, or std::vector<std::string>, or
dlib::std_vector_c<std::string>
ensures
- #keys == a queue containing all the keys defined in this config_reader's block.
(i.e. for all strings str in keys it is the case that is_key_defined(str) == true)
throws
- std::bad_alloc
If this exception is thrown then this call has no effect on *this and #keys is
unusable until keys.clear() is called and succeeds.
!*/
const std::string& current_block_name (
template <
typename queue_of_strings
>
void get_blocks (
queue_of_strings& blocks
) const;
/*!
requires
- current_element_valid() == true
ensures
- returns a string block_name such that: &block(block_name) == &element()
(i.e. returns the name of the block that the enumerator is currently at)
- queue_of_strings is an implementation of queue/queue_kernel_abstract.h
with T set to std::string, or std::vector<std::string>, or
dlib::std_vector_c<std::string>
ensures
- #blocks == a queue containing the names of all the blocks defined in this
config_reader's block.
(i.e. for all strings str in blocks it is the case that is_block_defined(str) == true)
!*/
private:
......
......@@ -19,7 +19,7 @@ namespace dlib
namespace logger_config_file_helpers
{
typedef config_reader::kernel_1a_c cr_type;
typedef config_reader::kernel_1a cr_type;
// ----------------------------------------------------------------------------------------
......@@ -122,9 +122,12 @@ namespace dlib
} // if (cr.is_key_defined("output"))
// now configure all the sub-blocks
cr.reset();
while (cr.move_next())
configure_sub_blocks(cr.element(), name + "." + cr.current_block_name());
std_vector_c<std::string> blocks;
cr.get_blocks(blocks);
for (unsigned long i = 0; i < blocks.size(); ++i)
{
configure_sub_blocks(cr.block(blocks[i]), name + "." + blocks[i]);
}
}
......@@ -184,9 +187,12 @@ namespace dlib
} // if (cr.is_key_defined("output"))
// now configure all the sub-blocks
cr.reset();
while (cr.move_next())
configure_sub_blocks(cr.element(),cr.current_block_name());
std_vector_c<std::string> blocks;
cr.get_blocks(blocks);
for (unsigned long i = 0; i < blocks.size(); ++i)
{
configure_sub_blocks(cr.block(blocks[i]), blocks[i]);
}
}
}
......
......@@ -20,6 +20,10 @@ namespace
using namespace dlib;
using namespace std;
// Declare the logger we will use in this test. The name of the tester
// should start with "test."
logger dlog("test.config_reader");
template <
typename config_reader
>
......@@ -31,14 +35,16 @@ namespace
DLIB_TEST(cr.is_block_defined("all"));
DLIB_TEST(cr.is_key_defined("globalasfd") == false);
DLIB_TEST(cr.is_block_defined("all!") == false);
DLIB_TEST(cr.size() == 1);
DLIB_TEST(cr["global"] == "hmm");
DLIB_TEST(cr["global2"] == "hmm2");
DLIB_TEST(cr.block("all").size() == 4);
DLIB_TEST(cr.block("all").block("block1").size() == 0);
DLIB_TEST(cr.block("all").block("block2").size() == 0);
DLIB_TEST(cr.block("all").block("block3").size() == 0);
DLIB_TEST(cr.block("all").block("block4").size() == 0);
std_vector_c<string> blocks;
cr.block("all").get_blocks(blocks);
DLIB_TEST(blocks.size() == 4);
cr.block("all").block("block1").get_blocks(blocks); DLIB_TEST(blocks.size() == 0);
cr.block("all").block("block2").get_blocks(blocks); DLIB_TEST(blocks.size() == 0);
cr.block("all").block("block3").get_blocks(blocks); DLIB_TEST(blocks.size() == 0);
cr.block("all").block("block4").get_blocks(blocks); DLIB_TEST(blocks.size() == 0);
DLIB_TEST(cr.block("all").block("block1").is_key_defined("name"));
DLIB_TEST(cr.block("all").block("block2").is_key_defined("name"));
......@@ -59,38 +65,92 @@ namespace
DLIB_TEST(cr.block("all").block("block4")["age"] == "53");
int count1 = 0;
int count2 = 0;
while (cr.move_next())
cr.get_blocks(blocks);
DLIB_TEST(blocks.size() == 1);
DLIB_TEST(blocks[0] == "all");
DLIB_TEST(cr.block("all").is_key_defined("global") == false);
DLIB_TEST(cr.block("all").is_key_defined("global2") == false);
DLIB_TEST(cr.block("all").is_key_defined("name") == false);
DLIB_TEST(cr.block("all").is_key_defined("age") == false);
cr.block("all").get_blocks(blocks);
DLIB_TEST(blocks.size() == 4);
std::vector<string> temp_blocks;
for (unsigned long i = 0; i < blocks.size(); ++i)
{
++count1;
DLIB_TEST(cr.current_block_name() == "all");
DLIB_TEST(cr.element().is_key_defined("global") == false);
DLIB_TEST(cr.element().is_key_defined("global2") == false);
DLIB_TEST(cr.element().is_key_defined("name") == false);
DLIB_TEST(cr.element().is_key_defined("age") == false);
while (cr.element().move_next())
{
++count2;
ostringstream sout;
sout << "block" << count2;
DLIB_TEST(cr.element().current_block_name() == sout.str());
DLIB_TEST(cr.element().size() == 4);
DLIB_TEST(cr.element().element().size() == 0);
DLIB_TEST(cr.element().element().is_key_defined("name"));
DLIB_TEST(cr.element().element().is_key_defined("age"));
}
++count2;
ostringstream sout;
sout << "block" << count2;
DLIB_TEST(blocks[i] == sout.str());
cr.block("all").block(blocks[i]).get_blocks(temp_blocks);
DLIB_TEST(temp_blocks.size() == 0);
DLIB_TEST(cr.block("all").block(blocks[i]).is_key_defined("name"));
DLIB_TEST(cr.block("all").block(blocks[i]).is_key_defined("age"));
}
DLIB_TEST(count1 == 1);
DLIB_TEST(count2 == 4);
bool found_error = false;
try
{
cr.block("bogus_block");
}
catch (typename config_reader::config_reader_access_error& e)
{
DLIB_TEST(e.block_name == "bogus_block");
DLIB_TEST(e.key_name == "");
found_error = true;
}
DLIB_TEST(found_error);
found_error = false;
try
{
cr["bogus_key"];
}
catch (typename config_reader::config_reader_access_error& e)
{
DLIB_TEST(e.block_name == "");
DLIB_TEST(e.key_name == "bogus_key");
found_error = true;
}
DLIB_TEST(found_error);
found_error = false;
try
{
cr.block("all").block("block10");
}
catch (typename config_reader::config_reader_access_error& e)
{
DLIB_TEST(e.block_name == "block10");
DLIB_TEST(e.key_name == "");
found_error = true;
}
DLIB_TEST(found_error);
found_error = false;
try
{
cr.block("all")["msdofg"];
}
catch (typename config_reader::config_reader_access_error& e)
{
DLIB_TEST(e.block_name == "");
DLIB_TEST(e.key_name == "msdofg");
found_error = true;
}
DLIB_TEST(found_error);
}
// Declare the logger we will use in this test. The name of the tester
// should start with "test."
logger dlog("test.config_reader");
template <
typename config_reader
......@@ -163,7 +223,6 @@ namespace
do_the_tests(cr2);
cr.clear();
DLIB_TEST(cr.size() == 0);
DLIB_TEST(cr.is_key_defined("global") == false);
}
......@@ -355,17 +414,9 @@ namespace
print_spinner();
config_reader_test<config_reader::kernel_1a>();
dlog << LINFO << "testing kernel_1a_c";
print_spinner();
config_reader_test<config_reader::kernel_1a_c>();
dlog << LINFO << "testing thread_safe_1a";
print_spinner();
config_reader_test<config_reader::thread_safe_1a>();
dlog << LINFO << "testing thread_safe_1a_c";
print_spinner();
config_reader_test<config_reader::thread_safe_1a_c>();
}
} a;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment